-Moodle - FirstClass authentication module\r
------------------------------------------\r
-This module uses the FirstClass Flexible Provisining Protocol (FPP) to communicate between the FirstClass server\r
-and the Moodle host. \r
-\r
-Installation\r
-------------\r
-\r
-1. Enable FPP on the FirstClass server\r
-FPP is not doumented in the FirstClass documentation and is not enable by default.\r
-To enable the protocol you need to edit the file \FCPO\Server\Netinfo. Open the file and insert the\r
-following lines. \r
-\r
-// TCP port for Flexible Provisioning Protocol (FPP).\r
-TCPFPPPORT = 3333\r
-\r
-\r
-2. Create an account on the FirstClass server with privilege "Subadministrator".\r
-Using the FPP protocoll this module logs in to the FirstClass server and issuess batch admin commands.\r
-Batch admin command can only be issued in the context of a user with subadministrative privileges.\r
-\r
-Default account name is "fcMoodle".\r
-\r
-\r
-3. Check that the FPP protocoll is working by running a Telnet session. If everyting is working you\r
-should get a "+0" answer from the server. \r
-\r
-> telnet yourhost.domain.com 3333\r
-+0\r
-\r
-Check that the "fcMoodle" is working by entering the following sequens of commands:\r
-\r
-> telnet yourhost.domain.com 3333\r
-+0\r
-fcMoodle\r
-+0\r
-\r
-the_password_you_gave_fcmoodle\r
-+0\r
-\r
-Get user some_user_id 1201\r
-\r
-1201 0 some_user_id\r
-+0\r
-\r
-\r
-\r
-4. On the Moodle host go to the directory where you have installed Moodle.\r
-Open the folder "auth", where all other authentication modules are installed,\r
- and create a new directory with the name "fc". \r
-\r
-Copy the files "config.html", "fcFPP.php" and "lib.php" to the "auth" directory.\r
-\r
-Now you need to add som strings to the language file. This distribution contains\r
-string for the English (en) and Swedish (sv) translation.\r
-\r
-Open the file "auth.php" in the folder "lang/sv" and paste the text from the file\r
-"auth.php - sv.txt" at the end of the file above the line "?>"\r
-\r
-Open the file "auth.php" in the folder "lang/en" and paste the text from the file\r
-"auth.php - en.txt" at the end of the file above the line "?>"\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
+Moodle - FirstClass authentication module
+-----------------------------------------
+This module uses the FirstClass Flexible Provisining Protocol (FPP) to communicate between the FirstClass server
+and the Moodle host.
+
+Installation
+------------
+
+1. Enable FPP on the FirstClass server
+FPP is not doumented in the FirstClass documentation and is not enable by default.
+To enable the protocol you need to edit the file \FCPO\Server\Netinfo. Open the file and insert the
+following lines.
+
+// TCP port for Flexible Provisioning Protocol (FPP).
+TCPFPPPORT = 3333
+
+
+2. Create an account on the FirstClass server with privilege "Subadministrator".
+Using the FPP protocoll this module logs in to the FirstClass server and issuess batch admin commands.
+Batch admin command can only be issued in the context of a user with subadministrative privileges.
+
+Default account name is "fcMoodle".
+
+
+3. Check that the FPP protocoll is working by running a Telnet session. If everyting is working you
+should get a "+0" answer from the server.
+
+> telnet yourhost.domain.com 3333
++0
+
+Check that the "fcMoodle" is working by entering the following sequens of commands:
+
+> telnet yourhost.domain.com 3333
++0
+fcMoodle
++0
+
+the_password_you_gave_fcmoodle
++0
+
+Get user some_user_id 1201
+
+1201 0 some_user_id
++0
+
+
+
+4. On the Moodle host go to the directory where you have installed Moodle.
+Open the folder "auth", where all other authentication modules are installed,
+ and create a new directory with the name "fc".
+
+Copy the files "config.html", "fcFPP.php" and "lib.php" to the "auth" directory.
+
+Now you need to add som strings to the language file. This distribution contains
+string for the English (en) and Swedish (sv) translation.
+
+Open the file "auth.php" in the folder "lang/sv" and paste the text from the file
+"auth.php - sv.txt" at the end of the file above the line "?>"
+
+Open the file "auth.php" in the folder "lang/en" and paste the text from the file
+"auth.php - en.txt" at the end of the file above the line "?>"
+
+
+
+
+
+
+
+
+
+
-<?php\r
-/************************************************************************/\r
-/* fcFPP: Php class for FirstClass Flexible Provisining Protocol */\r
-/* ============================================================= */\r
-/* */\r
-/* Copyright (c) 2004 SKERIA Utveckling, Teknous */\r
-/* http://skeria.skelleftea.se */\r
-/* */\r
-/* Flexible Provisioning Protocol is a real-time, IP based protocol */\r
-/* which provides direct access to the scriptable remote administration */\r
-/* subsystem of the core FirstClass Server. Using FPP, it is possible to*/\r
-/* implement automated provisioning and administration systems for */\r
-/* FirstClass, avoiding the need for a point and click GUI. FPP can also*/\r
-/* be used to integrate FirstClass components into a larger unified */\r
-/* system. */\r
-/* */\r
-/* This program is free software. You can redistribute it and/or modify */\r
-/* it under the terms of the GNU General Public License as published by */\r
-/* the Free Software Foundation; either version 2 of the License. */\r
-/************************************************************************/\r
-/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se\r
- */\r
-\r
-class fcFPP\r
-{ \r
- var $_hostname; // hostname of FirstClass server we are connection to\r
- var $_port; // port on which fpp is running\r
- var $_conn = 0; // socket we are connecting on\r
- var $_debug = FALSE; // set to true to see some debug info\r
- \r
- // class constructor\r
- function fcFPP($host="localhost", $port="3333")\r
- {\r
- $this->_hostname = $host;\r
- $this->_port = $port;\r
- $this->_user = "";\r
- $this->_pwd = ""; \r
- }\r
- \r
- // open a connection to the FirstClass server\r
- function open()\r
- {\r
- if($this->_debug) echo "Connecting to host ";\r
- $host = $this->_hostname;\r
- $port = $this->_port;\r
-\r
- if($this->_debug) echo "[$host:$port]..";\r
-\r
- // open the connection to the FirstClass server\r
- $conn = fsockopen($host, $port, $errno, $errstr, 5);\r
- if(!$conn)\r
- {\r
- echo "connection failed!".$errno. $errstr;\r
- return false;\r
- }\r
- \r
- // We are connected\r
- if($this->_debug) echo "connected!";\r
- \r
- // Read connection message.\r
- $line = fgets ($conn); //+0\r
- $line = fgets ($conn); //new line\r
-\r
- // store the connection in this class, so we can use it later\r
- $this->_conn = & $conn;\r
-\r
- return true;\r
- }\r
-\r
- // close any open connections\r
- function close()\r
- { \r
- // get the current connection\r
- $conn = &$this->_conn;\r
-\r
- // close it if it's open\r
- if($conn)\r
- {\r
- fclose($conn);\r
-\r
- // cleanup the variable\r
- unset($this->_conn);\r
- return true;\r
- }\r
- return;\r
- }\r
- \r
- \r
- // Authenticate to the FirstClass server\r
- function login($userid, $passwd)\r
- {\r
- // we did have a connection right?!\r
- if($this->_conn)\r
- {\r
- # Send username\r
- fputs($this->_conn,"$userid\r\n");\r
-\r
- $line = fgets ($this->_conn); //new line\r
- $line = fgets ($this->_conn); //+0\r
- $line = fgets ($this->_conn); //new line\r
- \r
- # Send password\r
- fputs($this->_conn,"$passwd\r\n");\r
- $line = fgets ($this->_conn); //new line\r
- $line = fgets ($this->_conn); //+0\r
- $line = fgets ($this->_conn); //+0 or message\r
- \r
- if($this->_debug) echo $line;\r
- \r
- if (preg_match ("/^\+0/", $line)) { //+0, user with subadmin privileges\r
- $this->_user = $userid;\r
- $this->_pwd = $passwd; \r
- return TRUE; \r
- } elseif (preg_match ("/^\Sorry/",$line)){ //Denied access but a valid user and password\r
- return TRUE;\r
- } else { //Invalid user or password\r
- return FALSE;\r
- }\r
- \r
-\r
- }\r
- return FALSE;\r
- }\r
-\r
- // Get the list of groups the user is a member of \r
- function getGroups($userid){\r
- \r
- $groups = array();\r
- \r
- // we must be logged in as a user with subadmin privileges \r
- if($this->_conn AND $this->_user) {\r
- # Send BA-command to get groups\r
- fputs($this->_conn,"GET USER '" . $userid . "' 4 -1\r");\r
- $line = "";\r
- while (!$line) {\r
- $line = trim(fgets ($this->_conn));\r
- }\r
- $n = 0;\r
- while ($line AND !preg_match("/^\+0/", $line) AND $line != "-1003") {\r
- list( , , $groups[$n++]) = explode(" ",$line,3);\r
- $line = trim(fgets ($this->_conn));\r
- }\r
- if($this->_debug) echo "getGroups:" . implode(",",$groups);\r
- }\r
- \r
- return $groups;\r
- }\r
-\r
- // Check if the user is member of any of the groups.\r
- // Return the list of groups the user is member of.\r
- function isMemberOf($userid, $groups){\r
- \r
- $usergroups = array_map("strtolower",$this->getGroups($userid));\r
- $groups = array_map("strtolower",$groups);\r
- \r
- $result = array_intersect($groups,$usergroups);\r
- \r
- if($this->_debug) echo "isMemberOf:" . implode(",",$result);\r
- \r
- return $result;\r
-\r
- }\r
- \r
- function getUserInfo($userid, $field){\r
- \r
- $userinfo = "";\r
- \r
- if($this->_conn AND $this->_user) {\r
- # Send BA-command to get data\r
- fputs($this->_conn,"GET USER '" . $userid . "' " . $field . "\r");\r
- $line = "";\r
- while (!$line) {\r
- $line = trim(fgets ($this->_conn));\r
- }\r
- $n = 0;\r
- while ($line AND !preg_match("/^\+0/", $line)) {\r
- list( , , $userinfo) = explode(" ",$line,3);\r
- $line = trim(fgets ($this->_conn));\r
- }\r
- if($this->_debug) echo "getUserInfo:" . $userinfo;\r
- }\r
- \r
- return str_replace('\r',' ',trim($userinfo,'"'));\r
-\r
- }\r
-\r
- function getResume($userid){\r
- \r
- $resume = "";\r
-\r
- $pattern = "/\[.+:.+\..+\]/"; // Remove references to pictures in resumes\r
- \r
- if($this->_conn AND $this->_user) {\r
- # Send BA-command to get data\r
- fputs($this->_conn,"GET RESUME '" . $userid . "' 6\r");\r
- $line = "";\r
- while (!$line) {\r
- $line = trim(fgets ($this->_conn));\r
- }\r
- $n = 0;\r
- while ($line AND !preg_match("/^\+0/", $line)) {\r
- $resume .= preg_replace($pattern,"",str_replace('\r',"\n",trim($line,'6 ')));\r
- $line = trim(fgets ($this->_conn));\r
- //print $line;\r
- \r
- }\r
- if($this->_debug) echo "getResume:" . $resume;\r
- }\r
- \r
- return $resume;\r
-\r
- }\r
- \r
- \r
-}\r
- \r
-\r
+<?php
+/************************************************************************/
+/* fcFPP: Php class for FirstClass Flexible Provisining Protocol */
+/* ============================================================= */
+/* */
+/* Copyright (c) 2004 SKERIA Utveckling, Teknous */
+/* http://skeria.skelleftea.se */
+/* */
+/* Flexible Provisioning Protocol is a real-time, IP based protocol */
+/* which provides direct access to the scriptable remote administration */
+/* subsystem of the core FirstClass Server. Using FPP, it is possible to*/
+/* implement automated provisioning and administration systems for */
+/* FirstClass, avoiding the need for a point and click GUI. FPP can also*/
+/* be used to integrate FirstClass components into a larger unified */
+/* system. */
+/* */
+/* This program 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 2 of the License. */
+/************************************************************************/
+/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se
+ */
+
+class fcFPP
+{
+ var $_hostname; // hostname of FirstClass server we are connection to
+ var $_port; // port on which fpp is running
+ var $_conn = 0; // socket we are connecting on
+ var $_debug = FALSE; // set to true to see some debug info
+
+ // class constructor
+ function fcFPP($host="localhost", $port="3333")
+ {
+ $this->_hostname = $host;
+ $this->_port = $port;
+ $this->_user = "";
+ $this->_pwd = "";
+ }
+
+ // open a connection to the FirstClass server
+ function open()
+ {
+ if($this->_debug) echo "Connecting to host ";
+ $host = $this->_hostname;
+ $port = $this->_port;
+
+ if($this->_debug) echo "[$host:$port]..";
+
+ // open the connection to the FirstClass server
+ $conn = fsockopen($host, $port, $errno, $errstr, 5);
+ if(!$conn)
+ {
+ echo "connection failed!".$errno. $errstr;
+ return false;
+ }
+
+ // We are connected
+ if($this->_debug) echo "connected!";
+
+ // Read connection message.
+ $line = fgets ($conn); //+0
+ $line = fgets ($conn); //new line
+
+ // store the connection in this class, so we can use it later
+ $this->_conn = & $conn;
+
+ return true;
+ }
+
+ // close any open connections
+ function close()
+ {
+ // get the current connection
+ $conn = &$this->_conn;
+
+ // close it if it's open
+ if($conn)
+ {
+ fclose($conn);
+
+ // cleanup the variable
+ unset($this->_conn);
+ return true;
+ }
+ return;
+ }
+
+
+ // Authenticate to the FirstClass server
+ function login($userid, $passwd)
+ {
+ // we did have a connection right?!
+ if($this->_conn)
+ {
+ # Send username
+ fputs($this->_conn,"$userid\r\n");
+
+ $line = fgets ($this->_conn); //new line
+ $line = fgets ($this->_conn); //+0
+ $line = fgets ($this->_conn); //new line
+
+ # Send password
+ fputs($this->_conn,"$passwd\r\n");
+ $line = fgets ($this->_conn); //new line
+ $line = fgets ($this->_conn); //+0
+ $line = fgets ($this->_conn); //+0 or message
+
+ if($this->_debug) echo $line;
+
+ if (preg_match ("/^\+0/", $line)) { //+0, user with subadmin privileges
+ $this->_user = $userid;
+ $this->_pwd = $passwd;
+ return TRUE;
+ } elseif (preg_match ("/^\Sorry/",$line)){ //Denied access but a valid user and password
+ return TRUE;
+ } else { //Invalid user or password
+ return FALSE;
+ }
+
+
+ }
+ return FALSE;
+ }
+
+ // Get the list of groups the user is a member of
+ function getGroups($userid){
+
+ $groups = array();
+
+ // we must be logged in as a user with subadmin privileges
+ if($this->_conn AND $this->_user) {
+ # Send BA-command to get groups
+ fputs($this->_conn,"GET USER '" . $userid . "' 4 -1\r");
+ $line = "";
+ while (!$line) {
+ $line = trim(fgets ($this->_conn));
+ }
+ $n = 0;
+ while ($line AND !preg_match("/^\+0/", $line) AND $line != "-1003") {
+ list( , , $groups[$n++]) = explode(" ",$line,3);
+ $line = trim(fgets ($this->_conn));
+ }
+ if($this->_debug) echo "getGroups:" . implode(",",$groups);
+ }
+
+ return $groups;
+ }
+
+ // Check if the user is member of any of the groups.
+ // Return the list of groups the user is member of.
+ function isMemberOf($userid, $groups){
+
+ $usergroups = array_map("strtolower",$this->getGroups($userid));
+ $groups = array_map("strtolower",$groups);
+
+ $result = array_intersect($groups,$usergroups);
+
+ if($this->_debug) echo "isMemberOf:" . implode(",",$result);
+
+ return $result;
+
+ }
+
+ function getUserInfo($userid, $field){
+
+ $userinfo = "";
+
+ if($this->_conn AND $this->_user) {
+ # Send BA-command to get data
+ fputs($this->_conn,"GET USER '" . $userid . "' " . $field . "\r");
+ $line = "";
+ while (!$line) {
+ $line = trim(fgets ($this->_conn));
+ }
+ $n = 0;
+ while ($line AND !preg_match("/^\+0/", $line)) {
+ list( , , $userinfo) = explode(" ",$line,3);
+ $line = trim(fgets ($this->_conn));
+ }
+ if($this->_debug) echo "getUserInfo:" . $userinfo;
+ }
+
+ return str_replace('\r',' ',trim($userinfo,'"'));
+
+ }
+
+ function getResume($userid){
+
+ $resume = "";
+
+ $pattern = "/\[.+:.+\..+\]/"; // Remove references to pictures in resumes
+
+ if($this->_conn AND $this->_user) {
+ # Send BA-command to get data
+ fputs($this->_conn,"GET RESUME '" . $userid . "' 6\r");
+ $line = "";
+ while (!$line) {
+ $line = trim(fgets ($this->_conn));
+ }
+ $n = 0;
+ while ($line AND !preg_match("/^\+0/", $line)) {
+ $resume .= preg_replace($pattern,"",str_replace('\r',"\n",trim($line,'6 ')));
+ $line = trim(fgets ($this->_conn));
+ //print $line;
+
+ }
+ if($this->_debug) echo "getResume:" . $resume;
+ }
+
+ return $resume;
+
+ }
+
+
+}
+
+
?>
\ No newline at end of file
-<?php // $Id$\r
- \r
-// FirstClass authentication using FirstClass Flexible Provisining Protocol\r
-\r
-/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se\r
-\r
-CHANGELOG\r
-\r
-README\r
- Module will authenticate user against FirstClass server and check if user belongs to any of\r
- the defined creator groups.\r
- User authenticates using their existing FirstClass username and password.\r
- Where possible userdata is copied from the FirstClass directory to Moodle. You may\r
- want to modify this.\r
- Module requires the fcFPP class to do it's jobb.\r
- */\r
- \r
-\r
-require('fcFPP.php');\r
- \r
-\r
-function auth_user_login ($username, $password) {\r
-/// Returns true if the username and password work\r
-/// and false if they don't\r
-\r
- global $CFG;\r
-\r
- $hostname = $CFG->auth_fchost;\r
- $port = $CFG->auth_fcfppport;\r
-\r
- $retval = FALSE;\r
-\r
- if (!$username or !$password) { // Don't allow blank usernames or passwords\r
- return $retval;\r
- }\r
-\r
-\r
- $fpp = new fcFPP($hostname,$port);\r
- if ($fpp->open()) {\r
- if ($fpp->login($username,$password)){\r
- $retval = TRUE;\r
- }\r
- }\r
- $fpp->close();\r
-\r
- return $retval;\r
- \r
-\r
-}\r
-\r
-function auth_get_userinfo($username){\r
-// Get user information from FirstCLass server and return it in an array.\r
-// Localize this routine to fit your needs. \r
-\r
-/*\r
-Moodle FirstCLass fieldID in UserInfo form\r
------- -----------------------------------\r
-firstname 1202\r
-lastname 1204\r
-email 1252\r
-icq -\r
-phone1 1206\r
-phone2 1207 (Fax)\r
-institution - \r
-department - \r
-address 1205\r
-city - \r
-country -\r
-lang -\r
-timezone 8030 (Not used yet. Need to figure out how FC codes timezones)\r
-\r
-description Get data from users resume. Pictures will be removed.\r
-\r
-*/\r
-\r
- global $CFG;\r
- \r
- $hostname = $CFG->auth_fchost;\r
- $port = $CFG->auth_fcfppport;\r
- $userid = $CFG->auth_fcuserid;\r
- $passwd = $CFG->auth_fcpasswd; \r
-\r
- $userinfo = array();\r
-\r
- $fpp = new fcFPP($hostname,$port);\r
- if ($fpp->open()) {\r
- if ($fpp->login($userid,$passwd)){\r
-\r
- $userinfo['firstname'] = $fpp->getUserInfo($username,"1202");\r
- $userinfo['lastname'] = $fpp->getUserInfo($username,"1204");\r
- $userinfo['email'] = strtok($fpp->getUserInfo($username,"1252"),',');\r
- $userinfo['phone1'] = $fpp->getUserInfo($username,"1206");\r
- $userinfo['phone2'] = $fpp->getUserInfo($username,"1207");\r
- $userinfo['description'] = $fpp->getResume($username);\r
-\r
- }\r
- }\r
-\r
- $fpp->close();\r
-\r
- foreach($userinfo as $key => $value) {\r
- if (!$value) {\r
- unset($userinfo[$key]);\r
- }\r
- }\r
- \r
- return $userinfo;\r
-\r
-}\r
-\r
-\r
-function auth_iscreator($username=0) {\r
-//Get users group membership from the FirstClass server user and check if\r
-// user is member of one of the groups of creators.\r
-\r
- global $CFG, $USER;\r
-\r
- if (! $CFG->auth_fccreators) {\r
- return false;\r
- }\r
-\r
- if (! $username) {\r
- $username=$USER->username;\r
- }\r
-\r
- $fcgroups = array();\r
-\r
- $hostname = $CFG->auth_fchost;\r
- $port = $CFG->auth_fcfppport;\r
- $userid = $CFG->auth_fcuserid;\r
- $passwd = $CFG->auth_fcpasswd; \r
-\r
- $fpp = new fcFPP($hostname,$port);\r
- if ($fpp->open()) {\r
- if ($fpp->login($userid,$passwd)){\r
- $fcgroups = $fpp->getGroups($username);\r
- }\r
- }\r
- $fpp->close();\r
-\r
- \r
- if ((! $fcgroups)) {\r
- return false;\r
- }\r
-\r
- $creators = explode(";",$CFG->auth_fccreators);\r
- \r
- foreach($creators as $creator) {\r
- If (in_array($creator, $fcgroups)) return true;\r
- }\r
- \r
- return false;\r
-}\r
- \r
+<?php // $Id$
+
+// FirstClass authentication using FirstClass Flexible Provisining Protocol
+
+/* Author: Torsten Anderson, torsten.anderson@skeria.skelleftea.se
+
+CHANGELOG
+
+README
+ Module will authenticate user against FirstClass server and check if user belongs to any of
+ the defined creator groups.
+ User authenticates using their existing FirstClass username and password.
+ Where possible userdata is copied from the FirstClass directory to Moodle. You may
+ want to modify this.
+ Module requires the fcFPP class to do it's jobb.
+ */
+
+
+require('fcFPP.php');
+
+
+function auth_user_login ($username, $password) {
+/// Returns true if the username and password work
+/// and false if they don't
+
+ global $CFG;
+
+ $hostname = $CFG->auth_fchost;
+ $port = $CFG->auth_fcfppport;
+
+ $retval = FALSE;
+
+ if (!$username or !$password) { // Don't allow blank usernames or passwords
+ return $retval;
+ }
+
+
+ $fpp = new fcFPP($hostname,$port);
+ if ($fpp->open()) {
+ if ($fpp->login($username,$password)){
+ $retval = TRUE;
+ }
+ }
+ $fpp->close();
+
+ return $retval;
+
+
+}
+
+function auth_get_userinfo($username){
+// Get user information from FirstCLass server and return it in an array.
+// Localize this routine to fit your needs.
+
+/*
+Moodle FirstCLass fieldID in UserInfo form
+------ -----------------------------------
+firstname 1202
+lastname 1204
+email 1252
+icq -
+phone1 1206
+phone2 1207 (Fax)
+institution -
+department -
+address 1205
+city -
+country -
+lang -
+timezone 8030 (Not used yet. Need to figure out how FC codes timezones)
+
+description Get data from users resume. Pictures will be removed.
+
+*/
+
+ global $CFG;
+
+ $hostname = $CFG->auth_fchost;
+ $port = $CFG->auth_fcfppport;
+ $userid = $CFG->auth_fcuserid;
+ $passwd = $CFG->auth_fcpasswd;
+
+ $userinfo = array();
+
+ $fpp = new fcFPP($hostname,$port);
+ if ($fpp->open()) {
+ if ($fpp->login($userid,$passwd)){
+
+ $userinfo['firstname'] = $fpp->getUserInfo($username,"1202");
+ $userinfo['lastname'] = $fpp->getUserInfo($username,"1204");
+ $userinfo['email'] = strtok($fpp->getUserInfo($username,"1252"),',');
+ $userinfo['phone1'] = $fpp->getUserInfo($username,"1206");
+ $userinfo['phone2'] = $fpp->getUserInfo($username,"1207");
+ $userinfo['description'] = $fpp->getResume($username);
+
+ }
+ }
+
+ $fpp->close();
+
+ foreach($userinfo as $key => $value) {
+ if (!$value) {
+ unset($userinfo[$key]);
+ }
+ }
+
+ return $userinfo;
+
+}
+
+
+function auth_iscreator($username=0) {
+//Get users group membership from the FirstClass server user and check if
+// user is member of one of the groups of creators.
+
+ global $CFG, $USER;
+
+ if (! $CFG->auth_fccreators) {
+ return false;
+ }
+
+ if (! $username) {
+ $username=$USER->username;
+ }
+
+ $fcgroups = array();
+
+ $hostname = $CFG->auth_fchost;
+ $port = $CFG->auth_fcfppport;
+ $userid = $CFG->auth_fcuserid;
+ $passwd = $CFG->auth_fcpasswd;
+
+ $fpp = new fcFPP($hostname,$port);
+ if ($fpp->open()) {
+ if ($fpp->login($userid,$passwd)){
+ $fcgroups = $fpp->getGroups($username);
+ }
+ }
+ $fpp->close();
+
+
+ if ((! $fcgroups)) {
+ return false;
+ }
+
+ $creators = explode(";",$CFG->auth_fccreators);
+
+ foreach($creators as $creator) {
+ If (in_array($creator, $fcgroups)) return true;
+ }
+
+ return false;
+}
+
-Moodle Language Packs\r
-\r
-This directory contains the standard packaged Moodle language files,\r
-for making the Moodle interface appear in different interfaces.\r
-\r
-The default language for Moodle is the English language, under the \r
-Unicode scheme (UTF8).\r
-\r
-To add more languages to Moodle, you can either:\r
-\r
- 1) use the Moodle languages GUI in the interface to fetch \r
- new languages and install them in your 'dataroot' directory.\r
-\r
- 2) download them and unzip the packs in this directory manually\r
-\r
-\r
-For more information, see the Moodle Documentation:\r
-\r
- http://docs.moodle.org/en/Translation\r
-\r
-\r
-Cheers,\r
-Moodle Development Team\r
+Moodle Language Packs
+
+This directory contains the standard packaged Moodle language files,
+for making the Moodle interface appear in different interfaces.
+
+The default language for Moodle is the English language, under the
+Unicode scheme (UTF8).
+
+To add more languages to Moodle, you can either:
+
+ 1) use the Moodle languages GUI in the interface to fetch
+ new languages and install them in your 'dataroot' directory.
+
+ 2) download them and unzip the packs in this directory manually
+
+
+For more information, see the Moodle Documentation:
+
+ http://docs.moodle.org/en/Translation
+
+
+Cheers,
+Moodle Development Team
-<p align="center"><b>Quick Grade</b></p>\r
-\r
-<p>With quickgrading enabled you can quickly grade multiple assignments on one page.</p>\r
-\r
-<p>Just change the grades and comments and use the Save button at the bottom to save \r
- all your changes for that page at once.</p>\r
-\r
-<p>The normal grading buttons on the right still work too in case you need more space. \r
- Your quickgrading preference is saved and will apply to all assignments in all courses.</p>\r
-\r
+<p align="center"><b>Quick Grade</b></p>
+
+<p>With quickgrading enabled you can quickly grade multiple assignments on one page.</p>
+
+<p>Just change the grades and comments and use the Save button at the bottom to save
+ all your changes for that page at once.</p>
+
+<p>The normal grading buttons on the right still work too in case you need more space.
+ Your quickgrading preference is saved and will apply to all assignments in all courses.</p>
+
-<p align="center"><b>Import PowerPoint HTML</b></p>\r
-<p> HOW TO USE</p>\r
-<p>All of the PowerPoint slides get imported as Branch Tables with Previous and Next answers.</p>\r
-<p>\r
-<ol>\r
-<li>Open up your PowerPoint presentation.</li>\r
-<li>Save it As a Web Page (no special options)</li>\r
-<li>The result of step 3 should be a htm file and a folder with all of the slides converted to web pages.<br />\r
- ZIP THE FOLDER only.</li>\r
-<li>Go to your moodle site and add a new lesson.</li>\r
-<li>After saving the lesson settings you should see 4 options under "What would you like to do first?" Click on "Import PowerPoint"</li>\r
-<li>Use to the "Browse..." button to find your zip file from step 3. Then click on "Upload this file"</li>\r
-<li>If everything worked, the next screen should just display a continue button.</li>\r
-</ol>\r
-</p>\r
-<p>If any images were in your PowerPoint, they would have been saved as course files in moddata/XY where X is your lesson's name and Y is a number (usually 0). Also, during the import process, files are created in your moodle data directory inside temp/lesson. These files are not deleted by importppt.php as of yet.</p>\r
-<p align="center"> </p>\r
-\r
+<p align="center"><b>Import PowerPoint HTML</b></p>
+<p> HOW TO USE</p>
+<p>All of the PowerPoint slides get imported as Branch Tables with Previous and Next answers.</p>
+<p>
+<ol>
+<li>Open up your PowerPoint presentation.</li>
+<li>Save it As a Web Page (no special options)</li>
+<li>The result of step 3 should be a htm file and a folder with all of the slides converted to web pages.<br />
+ ZIP THE FOLDER only.</li>
+<li>Go to your moodle site and add a new lesson.</li>
+<li>After saving the lesson settings you should see 4 options under "What would you like to do first?" Click on "Import PowerPoint"</li>
+<li>Use to the "Browse..." button to find your zip file from step 3. Then click on "Upload this file"</li>
+<li>If everything worked, the next screen should just display a continue button.</li>
+</ol>
+</p>
+<p>If any images were in your PowerPoint, they would have been saved as course files in moddata/XY where X is your lesson's name and Y is a number (usually 0). Also, during the import process, files are created in your moodle data directory inside temp/lesson. These files are not deleted by importppt.php as of yet.</p>
+<p align="center"> </p>
+
-<p align="center"><b>Question Option</b></p>\r
-\r
-<p>A few of the Question Types have an option which is activated by clicking on\r
- the checkbox. The question types and the meaning of the options are \r
- detailed below.</p>\r
-\r
-<ol>\r
-<li><p><b>Multichoice</b> There is variant of Multichoice questions called \r
- <b>"Multichoice Multianswer"</b> questions. If the Question \r
- Option is selected then the student is required to select all the \r
- correct answers from the set of answers. The question may or may not tell \r
- the student <i>how many</i> correct answers there are. For example "Which of the \r
- following were US Presidents?" does not, while "Select the two US \r
- presidents from the following list." does. The actual number of correct \r
- answers can be from <b>one</b> up to the number of choices. (A Multichoice \r
- Multianswer question with one correct answer <b>is</b> different from a \r
- Multichoice question as the former allows the student the possibility of \r
- choosing more than one answer while the latter does not.)</p></li>\r
-\r
-<li>\r
- <p><b>Short Answer</b> There are two different comparison systems available \r
- for the Short Answer type of question: the simple system is used by default; \r
- the "Regular Expressions" system is used if the "Use Regular \r
- Expressions" option box is checked. For more information, please read\r
- the Lesson question types help file.</p>\r
-</li>\r
-</ol>\r
-<p>The other Question Types do not use the Question Option.</p>\r
+<p align="center"><b>Question Option</b></p>
+
+<p>A few of the Question Types have an option which is activated by clicking on
+ the checkbox. The question types and the meaning of the options are
+ detailed below.</p>
+
+<ol>
+<li><p><b>Multichoice</b> There is variant of Multichoice questions called
+ <b>"Multichoice Multianswer"</b> questions. If the Question
+ Option is selected then the student is required to select all the
+ correct answers from the set of answers. The question may or may not tell
+ the student <i>how many</i> correct answers there are. For example "Which of the
+ following were US Presidents?" does not, while "Select the two US
+ presidents from the following list." does. The actual number of correct
+ answers can be from <b>one</b> up to the number of choices. (A Multichoice
+ Multianswer question with one correct answer <b>is</b> different from a
+ Multichoice question as the former allows the student the possibility of
+ choosing more than one answer while the latter does not.)</p></li>
+
+<li>
+ <p><b>Short Answer</b> There are two different comparison systems available
+ for the Short Answer type of question: the simple system is used by default;
+ the "Regular Expressions" system is used if the "Use Regular
+ Expressions" option box is checked. For more information, please read
+ the Lesson question types help file.</p>
+</li>
+</ol>
+<p>The other Question Types do not use the Question Option.</p>
-<p align="center"><b>Question Types</b></p>\r
-\r
-<p>The types of Questions currently supported by the Lesson module are:\r
-\r
-<ol>\r
-<li><p><b>Multichoice</b> This is the default question type. Multichoice questions\r
- are popular questions where the student is asked to choose one answer from a\r
- set of alternatives. The correct answer takes the student further into the\r
- lesson, the wrong answers do not. The wrong answers are sometimes called the\r
- "distractors" and the utility of these questions often rely more\r
- on the quality of the distractors than either the questions themselves or their\r
- correct answers.</p>\r
-\r
-<p> Each answer can optionally have a response. If no response is\r
- entered for an answer then the default response "That's the Correct\r
- Answer" or "That's the Wrong Answer" is shown to the student. </p>\r
-\r
-<p>It is possible to have more than one correct answer to a multichoice question.\r
- The different correct answers may give the student different responses and\r
- jump to different (forward) pages in the lesson but\r
- do not vary in their grades, (that is, some answers are <b>not</b> more correct\r
- than others, at least in terms of grade.) It is possible for all the answers\r
- to be correct and they might take the student to different (forward) parts of\r
- the lesson depending on which one is chosen.</p>\r
-\r
-<p>There is variant of Multichoice questions called <b>"Multichoice\r
- Multianswer"</b> questions. These require the student to select all the\r
- correct answers from the set of answers. The question may or may not tell\r
- the student how many correct answers there are. For example "Which of the\r
- following were US Presidents?" does not, while "Select the two US\r
- presidents from the following list." does. The actual number of correct\r
- answers can be from <b>one</b> up to the number of choices. (A Multichoice\r
- Multianswer question with one correct answer <b>is</b> different from a\r
- Multichoice question as the former allows the student the possibility of\r
- choosing more than one answer while the latter does not.)</p>\r
-\r
-<p>Again the correct answers are flagged using forward jumps, the wrong answers\r
- by same page or backward jumps. When there is more than one correct answer\r
- the jumps should all go to the same page, similarly with the wrong answers.\r
- If that is <b>not</b> the case a warning is given on the teacher's view of\r
- the lesson. The correct response, if required, should be given on the first\r
- correct answer and the wrong response, if required, should be on the first\r
- wrong answer. Responses on the other answers are ignored (without warning). </p></li>\r
-\r
-<li><p><b>Short Answer</b> </p>\r
- <p>The student is prompted for a short piece of text.\r
- This is checked against one or more answers. Answers can be either correct\r
- or wrong. Each answer can optionally have a response. If no response is\r
- entered for an answer then the default response "That's the Correct\r
- Answer" or "That's the Wrong Answer" is shown to the student.\r
- If the text entered does not match any of the answers the question is wrong\r
- and the student is shown the default wrong response.</p>\r
- <p><strong>There are two different comparison systems</strong> available for the \r
- Short Answer type of question: the simple system is used by default; the \r
- "Regular Expressions" system is used if the "Use Regular \r
- Expressions" option box is checked. </p>\r
- <ul>\r
- <li><strong>Simple analysis</strong>\r
- <p>In this (default) system of analysis, the comparisons ignore the case of the text. The \r
- asterisk (*) character can be used in answers as a "wild card"\r
- character. It stands for any number of characters (including no characters\r
- at all). For example, the answer "Long*" will match\r
- "longer", "longest" and "long". If one of\r
- the answers is just "*" (a single *) this answer will match\r
- anything, it is normally used as the last "catch-all" answer. The\r
- matching process goes through the answers in the order they appear on the\r
- screen. Once a match is found the process stops and the corresponding\r
- result (and response, if present) is returned. So, if for example the\r
- answers are Longest, Long* and * (in that order), the input\r
- "longer" will match the second answer and, in this case, the\r
- third answer, although a match, is ignored.</p>\r
- <p> If an asterisk (*) is actually needed in an answer, it should be entered as\r
- \*, backslash asterisk.</p>\r
- </li>\r
- </ul>\r
- <ul>\r
- <li><strong>Regular Expressions analysis</strong>\r
- <p>This system gives you access to a more powerful but more complicated system for \r
- analysing the student's answers. For a complete introduction to Regular Expressions, \r
- see these sites <a href="http://www.zend.com/zend/tut/tutorial-delin2.php" target="_blank">regular-expressions \r
- tutorial</a> or <a href="http://perso.wanadoo.fr/joseph.rezeau/eao/developpement/expandRegexpToString.htm#" \r
- target="_blank">rezeau.org</a>. </p>\r
- <h3>Correct answer matching a regular expression pattern </h3>\r
- <p>It is not possible to give complete examples of the vast possibilities offered \r
- by this system, and the following are just some possibilities. </p>\r
- <p><strong>Example 1.</strong> Suppose your question is "What are the colors \r
- of the French flag?". In the Answer 1 frame you type this regular \r
- expression: "<span class="c_computeroutput">it’s blue, white(,| and) \r
- red</span>/i". This will match any of those four student answers:</p>\r
- <ul>\r
- <li>it’s blue, white, red</li>\r
- <li>it’s blue, white and red</li>\r
- <li>It’s blue, white, red</li>\r
- <li>It’s blue, white and red </li>\r
- </ul>\r
- <p>Please note that by default a regular expression match is case sensitive; to \r
- make the match case insensitive you must add the <strong>/i</strong> parameter \r
- right at the end of your expression.</p>\r
- <p><strong>Example 2</strong>. Question: "What is blue, or red, or yellow?". \r
- Answer: "(|it's )a colou?r". This will match:</p>\r
- <ul>\r
- <li>a colour</li>\r
- <li> a color</li>\r
- <li>it's a colour</li>\r
- <li>it's a color</li>\r
- </ul>\r
- <p>Notes.- The beginning of this regular expression "(|it's )" will \r
- match either nothing or "it's " (i.e. "it's" followed by \r
- a space). The ? (question-mark) means: preceding character zero or one time; \r
- it is used here to match British English as well as US spelling.</p>\r
- <p><strong>Example 3.</strong> Question: "Name an animal whose name is made \r
- of 3 letters and the middle letter is the vowel <em>a</em>". Anwer: \r
- "[bcr]at". This will match: bat, cat and rat. </p>\r
- <h3>Detecting missing required words or character strings</h3>\r
- <p>Regular expressions alone cannot detect absent character strings, so you have to \r
- add a little code in your Answer to take care of this. Any Teacher Answer which \r
- begins with a double hyphen will analyse the student’s answer to find out \r
- whether the following string is present or absent. If present, the analysis \r
- continues to the next question; if absent, the analysis stops and the relevant \r
- Response message is displayed.</p>\r
- <p><strong>Example 4. </strong></p>\r
- <ul>\r
- <li>Answer 2: <span class="c_computeroutput">--.*blue.*</span>/i</li>\r
- <li>student answer: "it's red and white" </li>\r
- <li>Response 2: <span class="c_computeroutput">The color of the sky is missing!</span></li>\r
- <li>Jump 2: <span class="c_computeroutput">this page</span></li>\r
- </ul>\r
- <p>Here, the . (dot) stands for “any character” and the * (asterisk) \r
- means “preceding special character repeated any number of times”. \r
- The Answer2 regular expression above means: check whether the character string \r
- "blue", preceded with anything and followed by anything is absent \r
- from the student's answer. Please note that the use of the asterisk is different \r
- in the Simple analysis system and in the Regular Expressions system.</p>\r
- <p><strong>Example 5.</strong> Question: "Name an animal whose name is made of \r
- 3 letters and the middle letter is the vowel <em>a</em>". Teacher Answer: "--[b|c|r]". Response: "Your answer should start with one of these letters: b, c or r" </p>\r
- <h3>Detecting unwanted (incorrect) words or character strings</h3>\r
- <p>You may want to detect, in the student's answer, the presence of one or several \r
- words which should be <strong>not</strong> be there (because they are wrong) and \r
- to single them out with a specific response. Just start your teacher Answer by a \r
- double plus sign (++). </p>\r
- <p><strong>Example 6. </strong></p>\r
- <ul>\r
- <li>Answer 3: ++(yellow|black|orange|green|black|pink)/i</li>\r
- <li>student answer: "it's blue, orange and white" </li>\r
- <li>Response 3: One or more colors are wrong!</li>\r
- <li>Jump 3: this page</li></ul>\r
- <p>If any of these (wrong) colors is detected in the student’s answer, \r
- then the negative feedback message (Response 3) will be displayed and the \r
- wrong strings will be colored red (or the color of the .incorrect class if \r
- it exists in a CSS stylesheet of your active theme).</p>\r
- <p><strong>Example 7</strong>. Question: "Name an animal whose name is made \r
- of 3 letters and the middle letter is the vowel <em>a</em>". Teacher \r
- Answer: "++hat". Response: "You might wear one made of an \r
- animal's skin, but a hat can't be considered as an animal." </p>\r
- <h3>Escaping special characters </h3>\r
- <p>If you need to use characters which are part of the regular expressions set \r
- of <em>special characters</em>, you need to "escape" them (i.e. precede \r
- them with a backslash). E.g. if you want to accept the answer "My computer \r
- cost 1000$", you must write the regular expression as "My computer cost \r
- 1000\$". The special characters which must be escaped are .^$*()[]+?|</p>\r
- </li>\r
- </ul>\r
-</li>\r
-\r
-<li><p><b>True/False</b> The answer to this type of question only has two options,\r
- true or false. The student is prompted to choose which is the correct\r
- option. This type of question is basically a Multichoice question with just\r
- two choices.</p></li>\r
-\r
-<li><p><b>Matching</b> These are quite powerful and flexible questions. They\r
- consist of a list of names or statements which must be correctly matched\r
- against other list of names or statements. For example "Match the\r
- Capital with the Country" with the two lists Japan, Canada, Italy and\r
- Tokyo, Ottawa, Rome. It is possible to have repeated entries in one of the\r
- lists but care should be taken to make the repeats identical. For example\r
- "Identify the type of these creatures" with the lists Sparrow,\r
- Cow, Ant, Dog and Bird, Animal, Insect, Animal. </p>\r
-\r
-<p>When creating this type of question the items for the first list go into the\r
- Answer boxes and items for the second list go into the Response boxes. Once\r
- created a more sensible labeling scheme is shown. When the student\r
- successfully matches the items the jump on the first answer is used. An\r
- unsuccessful answer jumps to the page on the second answer. The question does\r
- <b>not</b> support custom responses, the student is told how many matches\r
- are correct or if all the matches are correct.</p>\r
-\r
-<p>Unlike the Multichoice question where the choices are shown in a random\r
- order, the first list of items is <b>not</b> shuffled but shown in the same\r
- order as entered. This allows for <b>"Ordered"</b> questions to be\r
- constructed. Consider the question " Put the following into the order\r
- they were born, the earliest first" with the lists 1., 2., 3., 4. and\r
- Longfellow, Lawrence, Lowell, Larkin. The second list is shuffed before\r
- being used in the question, of course.</p></li>\r
-\r
-<li><p><b>Numerical</b> This type of question requires a number as the answer.\r
- In it's simplest form it requires just one answer to be specified. For\r
- example "What is 2 plus 2?" with the answer 4 given a forward\r
- jump. However, it is better to specify a range because the internal rounding\r
- of numerical values can make single numeric comparisons rather hit or miss.\r
- Thus, if the question were "What is 10 divided by 3" it would be\r
- necessary to give the answer as <b>"Minimum:Maximum"</b>, that\r
- is <b>two</b> values separated by a colon (:). Thus if 3.33:3.34 is given as the\r
- acceptable range for the answer, then the answers 3.33, 3.333, 3.3333...\r
- would all be taken as correct answers. "Wrong" answers would\r
- include 3.3 (less than the minimum) and 3.4 (greater than the maximum).</p>\r
-\r
-<p>More than one correct answer is allowed and the answers can be either single\r
- or pair of values. Note that the order in which the answers are tested is\r
- Answer 1, Answer 2... so some care needs to taken if the desired response\r
- is to appear. For example the question "When was Larkin born?"\r
- could have the single value of 1922, the exact answer, and the pair of\r
- values 1920:1929, the 20's, as the less exact answer.The order in which\r
- these values should be tested is, obviously, 1922 then 1920:1929. The\r
- first answer might have the response "That's exactly right"\r
- while the other answer's response might be "That's close, you've got\r
- the right decade"</p>\r
-\r
-<p>Wrong answers can be given but depending on their actual range, care should\r
- be taken to place them after the correct answers. For example in adding the\r
- wrong answer 3:4 to the "10 divided by 3" question it needs to come\r
- after the correct answer. That is the answers are ordered 3.33:3.34 (the\r
- "correct" answer) then 3:4 (the "wrong" answer, but\r
- not wildly wrong answer!).</p></li>\r
-</ul>\r
-\r
+<p align="center"><b>Question Types</b></p>
+
+<p>The types of Questions currently supported by the Lesson module are:
+
+<ol>
+<li><p><b>Multichoice</b> This is the default question type. Multichoice questions
+ are popular questions where the student is asked to choose one answer from a
+ set of alternatives. The correct answer takes the student further into the
+ lesson, the wrong answers do not. The wrong answers are sometimes called the
+ "distractors" and the utility of these questions often rely more
+ on the quality of the distractors than either the questions themselves or their
+ correct answers.</p>
+
+<p> Each answer can optionally have a response. If no response is
+ entered for an answer then the default response "That's the Correct
+ Answer" or "That's the Wrong Answer" is shown to the student. </p>
+
+<p>It is possible to have more than one correct answer to a multichoice question.
+ The different correct answers may give the student different responses and
+ jump to different (forward) pages in the lesson but
+ do not vary in their grades, (that is, some answers are <b>not</b> more correct
+ than others, at least in terms of grade.) It is possible for all the answers
+ to be correct and they might take the student to different (forward) parts of
+ the lesson depending on which one is chosen.</p>
+
+<p>There is variant of Multichoice questions called <b>"Multichoice
+ Multianswer"</b> questions. These require the student to select all the
+ correct answers from the set of answers. The question may or may not tell
+ the student how many correct answers there are. For example "Which of the
+ following were US Presidents?" does not, while "Select the two US
+ presidents from the following list." does. The actual number of correct
+ answers can be from <b>one</b> up to the number of choices. (A Multichoice
+ Multianswer question with one correct answer <b>is</b> different from a
+ Multichoice question as the former allows the student the possibility of
+ choosing more than one answer while the latter does not.)</p>
+
+<p>Again the correct answers are flagged using forward jumps, the wrong answers
+ by same page or backward jumps. When there is more than one correct answer
+ the jumps should all go to the same page, similarly with the wrong answers.
+ If that is <b>not</b> the case a warning is given on the teacher's view of
+ the lesson. The correct response, if required, should be given on the first
+ correct answer and the wrong response, if required, should be on the first
+ wrong answer. Responses on the other answers are ignored (without warning). </p></li>
+
+<li><p><b>Short Answer</b> </p>
+ <p>The student is prompted for a short piece of text.
+ This is checked against one or more answers. Answers can be either correct
+ or wrong. Each answer can optionally have a response. If no response is
+ entered for an answer then the default response "That's the Correct
+ Answer" or "That's the Wrong Answer" is shown to the student.
+ If the text entered does not match any of the answers the question is wrong
+ and the student is shown the default wrong response.</p>
+ <p><strong>There are two different comparison systems</strong> available for the
+ Short Answer type of question: the simple system is used by default; the
+ "Regular Expressions" system is used if the "Use Regular
+ Expressions" option box is checked. </p>
+ <ul>
+ <li><strong>Simple analysis</strong>
+ <p>In this (default) system of analysis, the comparisons ignore the case of the text. The
+ asterisk (*) character can be used in answers as a "wild card"
+ character. It stands for any number of characters (including no characters
+ at all). For example, the answer "Long*" will match
+ "longer", "longest" and "long". If one of
+ the answers is just "*" (a single *) this answer will match
+ anything, it is normally used as the last "catch-all" answer. The
+ matching process goes through the answers in the order they appear on the
+ screen. Once a match is found the process stops and the corresponding
+ result (and response, if present) is returned. So, if for example the
+ answers are Longest, Long* and * (in that order), the input
+ "longer" will match the second answer and, in this case, the
+ third answer, although a match, is ignored.</p>
+ <p> If an asterisk (*) is actually needed in an answer, it should be entered as
+ \*, backslash asterisk.</p>
+ </li>
+ </ul>
+ <ul>
+ <li><strong>Regular Expressions analysis</strong>
+ <p>This system gives you access to a more powerful but more complicated system for
+ analysing the student's answers. For a complete introduction to Regular Expressions,
+ see these sites <a href="http://www.zend.com/zend/tut/tutorial-delin2.php" target="_blank">regular-expressions
+ tutorial</a> or <a href="http://perso.wanadoo.fr/joseph.rezeau/eao/developpement/expandRegexpToString.htm#"
+ target="_blank">rezeau.org</a>. </p>
+ <h3>Correct answer matching a regular expression pattern </h3>
+ <p>It is not possible to give complete examples of the vast possibilities offered
+ by this system, and the following are just some possibilities. </p>
+ <p><strong>Example 1.</strong> Suppose your question is "What are the colors
+ of the French flag?". In the Answer 1 frame you type this regular
+ expression: "<span class="c_computeroutput">it’s blue, white(,| and)
+ red</span>/i". This will match any of those four student answers:</p>
+ <ul>
+ <li>it’s blue, white, red</li>
+ <li>it’s blue, white and red</li>
+ <li>It’s blue, white, red</li>
+ <li>It’s blue, white and red </li>
+ </ul>
+ <p>Please note that by default a regular expression match is case sensitive; to
+ make the match case insensitive you must add the <strong>/i</strong> parameter
+ right at the end of your expression.</p>
+ <p><strong>Example 2</strong>. Question: "What is blue, or red, or yellow?".
+ Answer: "(|it's )a colou?r". This will match:</p>
+ <ul>
+ <li>a colour</li>
+ <li> a color</li>
+ <li>it's a colour</li>
+ <li>it's a color</li>
+ </ul>
+ <p>Notes.- The beginning of this regular expression "(|it's )" will
+ match either nothing or "it's " (i.e. "it's" followed by
+ a space). The ? (question-mark) means: preceding character zero or one time;
+ it is used here to match British English as well as US spelling.</p>
+ <p><strong>Example 3.</strong> Question: "Name an animal whose name is made
+ of 3 letters and the middle letter is the vowel <em>a</em>". Anwer:
+ "[bcr]at". This will match: bat, cat and rat. </p>
+ <h3>Detecting missing required words or character strings</h3>
+ <p>Regular expressions alone cannot detect absent character strings, so you have to
+ add a little code in your Answer to take care of this. Any Teacher Answer which
+ begins with a double hyphen will analyse the student’s answer to find out
+ whether the following string is present or absent. If present, the analysis
+ continues to the next question; if absent, the analysis stops and the relevant
+ Response message is displayed.</p>
+ <p><strong>Example 4. </strong></p>
+ <ul>
+ <li>Answer 2: <span class="c_computeroutput">--.*blue.*</span>/i</li>
+ <li>student answer: "it's red and white" </li>
+ <li>Response 2: <span class="c_computeroutput">The color of the sky is missing!</span></li>
+ <li>Jump 2: <span class="c_computeroutput">this page</span></li>
+ </ul>
+ <p>Here, the . (dot) stands for “any character” and the * (asterisk)
+ means “preceding special character repeated any number of times”.
+ The Answer2 regular expression above means: check whether the character string
+ "blue", preceded with anything and followed by anything is absent
+ from the student's answer. Please note that the use of the asterisk is different
+ in the Simple analysis system and in the Regular Expressions system.</p>
+ <p><strong>Example 5.</strong> Question: "Name an animal whose name is made of
+ 3 letters and the middle letter is the vowel <em>a</em>". Teacher Answer: "--[b|c|r]". Response: "Your answer should start with one of these letters: b, c or r" </p>
+ <h3>Detecting unwanted (incorrect) words or character strings</h3>
+ <p>You may want to detect, in the student's answer, the presence of one or several
+ words which should be <strong>not</strong> be there (because they are wrong) and
+ to single them out with a specific response. Just start your teacher Answer by a
+ double plus sign (++). </p>
+ <p><strong>Example 6. </strong></p>
+ <ul>
+ <li>Answer 3: ++(yellow|black|orange|green|black|pink)/i</li>
+ <li>student answer: "it's blue, orange and white" </li>
+ <li>Response 3: One or more colors are wrong!</li>
+ <li>Jump 3: this page</li></ul>
+ <p>If any of these (wrong) colors is detected in the student’s answer,
+ then the negative feedback message (Response 3) will be displayed and the
+ wrong strings will be colored red (or the color of the .incorrect class if
+ it exists in a CSS stylesheet of your active theme).</p>
+ <p><strong>Example 7</strong>. Question: "Name an animal whose name is made
+ of 3 letters and the middle letter is the vowel <em>a</em>". Teacher
+ Answer: "++hat". Response: "You might wear one made of an
+ animal's skin, but a hat can't be considered as an animal." </p>
+ <h3>Escaping special characters </h3>
+ <p>If you need to use characters which are part of the regular expressions set
+ of <em>special characters</em>, you need to "escape" them (i.e. precede
+ them with a backslash). E.g. if you want to accept the answer "My computer
+ cost 1000$", you must write the regular expression as "My computer cost
+ 1000\$". The special characters which must be escaped are .^$*()[]+?|</p>
+ </li>
+ </ul>
+</li>
+
+<li><p><b>True/False</b> The answer to this type of question only has two options,
+ true or false. The student is prompted to choose which is the correct
+ option. This type of question is basically a Multichoice question with just
+ two choices.</p></li>
+
+<li><p><b>Matching</b> These are quite powerful and flexible questions. They
+ consist of a list of names or statements which must be correctly matched
+ against other list of names or statements. For example "Match the
+ Capital with the Country" with the two lists Japan, Canada, Italy and
+ Tokyo, Ottawa, Rome. It is possible to have repeated entries in one of the
+ lists but care should be taken to make the repeats identical. For example
+ "Identify the type of these creatures" with the lists Sparrow,
+ Cow, Ant, Dog and Bird, Animal, Insect, Animal. </p>
+
+<p>When creating this type of question the items for the first list go into the
+ Answer boxes and items for the second list go into the Response boxes. Once
+ created a more sensible labeling scheme is shown. When the student
+ successfully matches the items the jump on the first answer is used. An
+ unsuccessful answer jumps to the page on the second answer. The question does
+ <b>not</b> support custom responses, the student is told how many matches
+ are correct or if all the matches are correct.</p>
+
+<p>Unlike the Multichoice question where the choices are shown in a random
+ order, the first list of items is <b>not</b> shuffled but shown in the same
+ order as entered. This allows for <b>"Ordered"</b> questions to be
+ constructed. Consider the question " Put the following into the order
+ they were born, the earliest first" with the lists 1., 2., 3., 4. and
+ Longfellow, Lawrence, Lowell, Larkin. The second list is shuffed before
+ being used in the question, of course.</p></li>
+
+<li><p><b>Numerical</b> This type of question requires a number as the answer.
+ In it's simplest form it requires just one answer to be specified. For
+ example "What is 2 plus 2?" with the answer 4 given a forward
+ jump. However, it is better to specify a range because the internal rounding
+ of numerical values can make single numeric comparisons rather hit or miss.
+ Thus, if the question were "What is 10 divided by 3" it would be
+ necessary to give the answer as <b>"Minimum:Maximum"</b>, that
+ is <b>two</b> values separated by a colon (:). Thus if 3.33:3.34 is given as the
+ acceptable range for the answer, then the answers 3.33, 3.333, 3.3333...
+ would all be taken as correct answers. "Wrong" answers would
+ include 3.3 (less than the minimum) and 3.4 (greater than the maximum).</p>
+
+<p>More than one correct answer is allowed and the answers can be either single
+ or pair of values. Note that the order in which the answers are tested is
+ Answer 1, Answer 2... so some care needs to taken if the desired response
+ is to appear. For example the question "When was Larkin born?"
+ could have the single value of 1922, the exact answer, and the pair of
+ values 1920:1929, the 20's, as the less exact answer.The order in which
+ these values should be tested is, obviously, 1922 then 1920:1929. The
+ first answer might have the response "That's exactly right"
+ while the other answer's response might be "That's close, you've got
+ the right decade"</p>
+
+<p>Wrong answers can be given but depending on their actual range, care should
+ be taken to place them after the correct answers. For example in adding the
+ wrong answer 3:4 to the "10 divided by 3" question it needs to come
+ after the correct answer. That is the answers are ordered 3.33:3.34 (the
+ "correct" answer) then 3:4 (the "wrong" answer, but
+ not wildly wrong answer!).</p></li>
+</ul>
+
-<p align="center"><b>Upload groups</b></p>\r
-\r
-<p>This facility allows the batch upload of groups into Moodle.</p>\r
-\r
-\r
-<ul>\r
- <li>Each line of the file contains one record</li>\r
- <li>Each record is a series of data separated by commas</li>\r
- <li>The first record of the file is special, and contains a list of fieldnames. This defines the format of the rest of the file.\r
- <blockquote>\r
- <p><strong>Required fieldnames:</strong> these fields must be included in the first record, and defined for each user</p>\r
- <p></p>\r
- <font color="#990000" face="Courier New, Courier, mono">groupname</font></p>\r
-</p>\r
- <p><strong>Default fieldnames:</strong> these are optional - if they are not included then the values are taken from the current language and current course</p>\r
- <p><font color="#990000" face="Courier New, Courier, mono">idnumber, coursename, lang</font> </p>\r
- <p><strong>Optional fieldnames: </strong>all of these are completely optional. </p>\r
- <p> <font color="#990000" face="Courier New, Courier, mono">description, picture, hidepicture</font></p>\r
- </blockquote>\r
- </li>\r
- <li>Commas within the data should be encoded as &#44 - the script will automatically decode these back to commas. </li>\r
- <li>For Boolean fields, use 0 for false and 1 for true. </li>\r
- <li>Either idnumber or coursename can be used to identify the course. Idnumber overrides coursename. If neither is specified, the groups will be added to the current course.\r
- <li>Coursename is the course shortname.</li>\r
- <li>Note: If a group is already registered in the Moodle database for a particular course, this script will return the \r
- group name for that group. Teachers are only allowed to upload groups in courses they are authorized to edit.</li>\r
-</ul>\r
- \r
-<p>Here is an example of a valid import file:</p>\r
-<p><font size="-1" face="Courier New, Courier, mono"></font>groupname,idnumber,lang,description,picture <br />\r
-group1, Phil101, en, this group requires extra attention!, 0 <br />\r
-group2, Math243, , ,\r
-</font></p>\r
-\r
+<p align="center"><b>Upload groups</b></p>
+
+<p>This facility allows the batch upload of groups into Moodle.</p>
+
+
+<ul>
+ <li>Each line of the file contains one record</li>
+ <li>Each record is a series of data separated by commas</li>
+ <li>The first record of the file is special, and contains a list of fieldnames. This defines the format of the rest of the file.
+ <blockquote>
+ <p><strong>Required fieldnames:</strong> these fields must be included in the first record, and defined for each user</p>
+ <p></p>
+ <font color="#990000" face="Courier New, Courier, mono">groupname</font></p>
+</p>
+ <p><strong>Default fieldnames:</strong> these are optional - if they are not included then the values are taken from the current language and current course</p>
+ <p><font color="#990000" face="Courier New, Courier, mono">idnumber, coursename, lang</font> </p>
+ <p><strong>Optional fieldnames: </strong>all of these are completely optional. </p>
+ <p> <font color="#990000" face="Courier New, Courier, mono">description, picture, hidepicture</font></p>
+ </blockquote>
+ </li>
+ <li>Commas within the data should be encoded as &#44 - the script will automatically decode these back to commas. </li>
+ <li>For Boolean fields, use 0 for false and 1 for true. </li>
+ <li>Either idnumber or coursename can be used to identify the course. Idnumber overrides coursename. If neither is specified, the groups will be added to the current course.
+ <li>Coursename is the course shortname.</li>
+ <li>Note: If a group is already registered in the Moodle database for a particular course, this script will return the
+ group name for that group. Teachers are only allowed to upload groups in courses they are authorized to edit.</li>
+</ul>
+
+<p>Here is an example of a valid import file:</p>
+<p><font size="-1" face="Courier New, Courier, mono"></font>groupname,idnumber,lang,description,picture <br />
+group1, Phil101, en, this group requires extra attention!, 0 <br />
+group2, Math243, , ,
+</font></p>
+
-<?php \r
-\r
-$string['createSequence'] = 'Create new sequence';\r
-$string['editSequence'] = 'Edit selected sequence';\r
-$string['error'] = 'Sorry, an unknown error has occured.';\r
-$string['introduction'] = 'Introduction';\r
-$string['lams'] = '-- LAMS - Learning Activity Management System --';\r
-$string['lamsoutline'] = 'LAMS Outline';\r
-$string['lesson']="learning session";\r
-$string['modulename'] = 'LAMS';\r
-$string['modulenameplural'] = 'LAMS';\r
-$string['notsetup'] = 'NOT_SET_UP';\r
-$string['openauthor'] = 'Open LAMS Author';\r
-$string['openlearner'] = 'Open LAMS Learner';\r
-$string['openmonitor'] = 'Open LAMS Monitor';\r
-$string['refreshSequenceList'] = 'Refresh sequence list';\r
-$string['selectExistingSequence'] = 'Select an existing sequence or create a new sequence.';\r
-$string['sequence'] = 'Select Sequence';\r
-$string['serverid'] = 'Enter the server ID received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';\r
-$string['serverkey'] = 'Enter the server key received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';\r
-$string['serverurl'] = 'Enter the basic URL used to access the LAMS server. For example http://localhost:8080/lams';\r
-$string['useSequence'] = 'Use selected sequence';\r
-$string['visibletostudents'] = 'Show activity to students';\r
-$string['wikistartederror'] = 'Wiki already has entries - can\'t change.';\r
-$string['workspace'] = 'Select Workspace';\r
-$string['wrongversionrange'] = '$a is not a correct range!';\r
-\r
-?>\r
+<?php
+
+$string['createSequence'] = 'Create new sequence';
+$string['editSequence'] = 'Edit selected sequence';
+$string['error'] = 'Sorry, an unknown error has occured.';
+$string['introduction'] = 'Introduction';
+$string['lams'] = '-- LAMS - Learning Activity Management System --';
+$string['lamsoutline'] = 'LAMS Outline';
+$string['lesson']="learning session";
+$string['modulename'] = 'LAMS';
+$string['modulenameplural'] = 'LAMS';
+$string['notsetup'] = 'NOT_SET_UP';
+$string['openauthor'] = 'Open LAMS Author';
+$string['openlearner'] = 'Open LAMS Learner';
+$string['openmonitor'] = 'Open LAMS Monitor';
+$string['refreshSequenceList'] = 'Refresh sequence list';
+$string['selectExistingSequence'] = 'Select an existing sequence or create a new sequence.';
+$string['sequence'] = 'Select Sequence';
+$string['serverid'] = 'Enter the server ID received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';
+$string['serverkey'] = 'Enter the server key received from <a href=http://www.lamsinternational.com target=_blank>LAMS international</a>.';
+$string['serverurl'] = 'Enter the basic URL used to access the LAMS server. For example http://localhost:8080/lams';
+$string['useSequence'] = 'Use selected sequence';
+$string['visibletostudents'] = 'Show activity to students';
+$string['wikistartederror'] = 'Wiki already has entries - can\'t change.';
+$string['workspace'] = 'Select Workspace';
+$string['wrongversionrange'] = '$a is not a correct range!';
+
+?>
-\r
-<?php \r
- // only display this help message if we are being forced to change\r
- if ($forcepassword) {\r
- notify( get_string('forcepasswordchangenotice') );\r
- }\r
- ?>\r
-<p><b><?php print_string("allfieldsrequired") ?></b></p>\r
-<?php\r
- if (empty($frm->username)) {\r
- $frm->username = "";\r
- }\r
- if (empty($frm->password)) {\r
- $frm->password = "";\r
- }\r
- if (empty($frm->newpassword1)) {\r
- $frm->newpassword1 = "";\r
- }\r
- if (empty($frm->newpassword2)) {\r
- $frm->newpassword2 = "";\r
- }\r
-?>\r
-<form action="change_password.php" method="post" name="form" id="form">\r
-<table cellpadding="10">\r
-\r
-<tr valign="top">\r
- <td><?php print_string("username") ?>:</td>\r
- <td>\r
- <?php if (has_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID)) || empty($frm->username)) { ?>\r
- <input type="text" name="username" size="25" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />\r
- <?php } else { ?>\r
- <input type="hidden" name="username" value="<?php p($frm->username)?>" /> <?php p($frm->username)?>\r
- <?php } ?>\r
- <?php if (!empty($err->username)) { formerr($err->username); } ?>\r
- </td>\r
-</tr>\r
-\r
-<?php if (!ihas_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID))) { ?>\r
- <tr valign="top">\r
- <td><?php print_string("oldpassword") ?>:</td>\r
- <td><input type="password" name="password" size="25" value="<?php p($frm->password) ?>" alt="<?php print_string("password") ?>" />\r
- <?php if (!empty($err->password)) { formerr($err->password); } ?>\r
- </td>\r
- </tr>\r
-<?php } ?>\r
-\r
-<tr valign="top">\r
- <td><?php print_string("newpassword") ?>:</td>\r
- <td><input type="password" name="newpassword1" size="25" value="<?php p($frm->newpassword1) ?>" alt="<?php print_string("newpassword") ?>" />\r
- <?php if (!empty($err->newpassword1)) { formerr($err->newpassword1); } ?>\r
- </td>\r
-</tr>\r
-<tr valign="top">\r
- <td><?php print_string("newpassword") ?> (<?php print_string("again") ?>):</td>\r
- <td><input type="password" name="newpassword2" size="25" value="<?php p($frm->newpassword2) ?>" alt="<?php print_string("newpassword") ?> (<?php print_string("again") ?>)" />\r
- <?php if (!empty($err->newpassword2)) { formerr($err->newpassword2); } ?>\r
- </td>\r
-</tr>\r
-<tr>\r
- <td></td>\r
- <td><input type="hidden" name="id" value="<?php p($frm->id)?>" />\r
- <input type="submit" value="<?php print_string("changepassword") ?>" /></td>\r
- </tr>\r
- </table>\r
-</form>\r
+
+<?php
+ // only display this help message if we are being forced to change
+ if ($forcepassword) {
+ notify( get_string('forcepasswordchangenotice') );
+ }
+ ?>
+<p><b><?php print_string("allfieldsrequired") ?></b></p>
+<?php
+ if (empty($frm->username)) {
+ $frm->username = "";
+ }
+ if (empty($frm->password)) {
+ $frm->password = "";
+ }
+ if (empty($frm->newpassword1)) {
+ $frm->newpassword1 = "";
+ }
+ if (empty($frm->newpassword2)) {
+ $frm->newpassword2 = "";
+ }
+?>
+<form action="change_password.php" method="post" name="form" id="form">
+<table cellpadding="10">
+
+<tr valign="top">
+ <td><?php print_string("username") ?>:</td>
+ <td>
+ <?php if (has_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID)) || empty($frm->username)) { ?>
+ <input type="text" name="username" size="25" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />
+ <?php } else { ?>
+ <input type="hidden" name="username" value="<?php p($frm->username)?>" /> <?php p($frm->username)?>
+ <?php } ?>
+ <?php if (!empty($err->username)) { formerr($err->username); } ?>
+ </td>
+</tr>
+
+<?php if (!ihas_capability('moodle/user:update',get_context_instance(CONTEXT_SYSTEM, SITEID))) { ?>
+ <tr valign="top">
+ <td><?php print_string("oldpassword") ?>:</td>
+ <td><input type="password" name="password" size="25" value="<?php p($frm->password) ?>" alt="<?php print_string("password") ?>" />
+ <?php if (!empty($err->password)) { formerr($err->password); } ?>
+ </td>
+ </tr>
+<?php } ?>
+
+<tr valign="top">
+ <td><?php print_string("newpassword") ?>:</td>
+ <td><input type="password" name="newpassword1" size="25" value="<?php p($frm->newpassword1) ?>" alt="<?php print_string("newpassword") ?>" />
+ <?php if (!empty($err->newpassword1)) { formerr($err->newpassword1); } ?>
+ </td>
+</tr>
+<tr valign="top">
+ <td><?php print_string("newpassword") ?> (<?php print_string("again") ?>):</td>
+ <td><input type="password" name="newpassword2" size="25" value="<?php p($frm->newpassword2) ?>" alt="<?php print_string("newpassword") ?> (<?php print_string("again") ?>)" />
+ <?php if (!empty($err->newpassword2)) { formerr($err->newpassword2); } ?>
+ </td>
+</tr>
+<tr>
+ <td></td>
+ <td><input type="hidden" name="id" value="<?php p($frm->id)?>" />
+ <input type="submit" value="<?php print_string("changepassword") ?>" /></td>
+ </tr>
+ </table>
+</form>
-<?php\r
- if (empty($form->resubmit)) {\r
- $form->resubmit = 0; //upload&rev: =1\r
- }\r
- if (empty($form->maxbytes)) {\r
- $form->maxbytes = $CFG->assignment_maxbytes;\r
- }\r
- if (empty($form->emailteachers)) {\r
- $form->emailteachers = '';\r
- }\r
- //allow multiple files (from new upload type)\r
- if (empty($form->var1)) {\r
- $form->var1 = 0; \r
- }\r
- //email to students (from upload&review)\r
- if (empty($form->var2)) {\r
- $form->var2 = '';\r
- }\r
-\r
-?>\r
-\r
-<table align="center" cellpadding="5" cellspacing="0">\r
-\r
-<tr valign="top">\r
- <td align="right"><b><?php print_string("maximumsize", "assignment") ?>:</b></td>\r
- <td>\r
- <?php\r
- $choices = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes);\r
- choose_from_menu ($choices, "maxbytes", $form->maxbytes, "");\r
- ?>\r
- </td>\r
-</tr>\r
-<tr>\r
- <td align="right"><b><?php print_string("allowmultiple", "assignment") ?>:</b></td>\r
- <td>\r
- <?php\r
- $options[0] = get_string("no"); $options[1] = get_string("yes");\r
- choose_from_menu($options, "var1", $form->var1, "");\r
- ?>\r
- </td>\r
-</tr>\r
-\r
-<tr>\r
- <td align="right"><b><?php print_string("allowresubmit", "assignment") ?>:</b></td>\r
- <td>\r
- <?php \r
- $options[0] = get_string("no"); $options[1] = get_string("yes");\r
- choose_from_menu($options, "resubmit", $form->resubmit, ""); //that's how it's un U&R\r
- // choose_from_menu($options, "var2", $form->var2, "");\r
- helpbutton("resubmit", get_string("allowresubmit", "assignment"), "assignment");\r
- ?>\r
- </td>\r
-</tr>\r
-\r
-<tr>\r
- <td align="right"><b><?php print_string("emailteachers", "assignment") ?>:</b></td>\r
- <td>\r
- <?php \r
- $options[0] = get_string("no"); $options[1] = get_string("yes");\r
- choose_from_menu($options, "emailteachers", $form->emailteachers, "");\r
- helpbutton("emailteachers", get_string("emailteachers", "assignment"), "assignment");\r
- ?>\r
- </td>\r
-</tr>\r
-<tr>\r
- <td align="right"><b><?php print_string("emailstudents", "assignment") ?>:</b></td>\r
- <td>\r
- <?php\r
- $options[0] = get_string("no"); $options[1] = get_string("yes");\r
- choose_from_menu($options, "var2", $form->var2, "");\r
- // choose_from_menu($options, "emailstudents", $form->emailstudents, "");\r
- helpbutton("emailstudents", get_string("emailstudents", "assignment"), "assignment");\r
- ?>\r
- </td>\r
-</tr>\r
-\r
-</table>\r
-\r
-<center>\r
-<br />\r
-<input type="submit" value="<?php print_string("continue") ?>" />\r
-</center>\r
+<?php
+ if (empty($form->resubmit)) {
+ $form->resubmit = 0; //upload&rev: =1
+ }
+ if (empty($form->maxbytes)) {
+ $form->maxbytes = $CFG->assignment_maxbytes;
+ }
+ if (empty($form->emailteachers)) {
+ $form->emailteachers = '';
+ }
+ //allow multiple files (from new upload type)
+ if (empty($form->var1)) {
+ $form->var1 = 0;
+ }
+ //email to students (from upload&review)
+ if (empty($form->var2)) {
+ $form->var2 = '';
+ }
+
+?>
+
+<table align="center" cellpadding="5" cellspacing="0">
+
+<tr valign="top">
+ <td align="right"><b><?php print_string("maximumsize", "assignment") ?>:</b></td>
+ <td>
+ <?php
+ $choices = get_max_upload_sizes($CFG->maxbytes, $this->course->maxbytes);
+ choose_from_menu ($choices, "maxbytes", $form->maxbytes, "");
+ ?>
+ </td>
+</tr>
+<tr>
+ <td align="right"><b><?php print_string("allowmultiple", "assignment") ?>:</b></td>
+ <td>
+ <?php
+ $options[0] = get_string("no"); $options[1] = get_string("yes");
+ choose_from_menu($options, "var1", $form->var1, "");
+ ?>
+ </td>
+</tr>
+
+<tr>
+ <td align="right"><b><?php print_string("allowresubmit", "assignment") ?>:</b></td>
+ <td>
+ <?php
+ $options[0] = get_string("no"); $options[1] = get_string("yes");
+ choose_from_menu($options, "resubmit", $form->resubmit, ""); //that's how it's un U&R
+ // choose_from_menu($options, "var2", $form->var2, "");
+ helpbutton("resubmit", get_string("allowresubmit", "assignment"), "assignment");
+ ?>
+ </td>
+</tr>
+
+<tr>
+ <td align="right"><b><?php print_string("emailteachers", "assignment") ?>:</b></td>
+ <td>
+ <?php
+ $options[0] = get_string("no"); $options[1] = get_string("yes");
+ choose_from_menu($options, "emailteachers", $form->emailteachers, "");
+ helpbutton("emailteachers", get_string("emailteachers", "assignment"), "assignment");
+ ?>
+ </td>
+</tr>
+<tr>
+ <td align="right"><b><?php print_string("emailstudents", "assignment") ?>:</b></td>
+ <td>
+ <?php
+ $options[0] = get_string("no"); $options[1] = get_string("yes");
+ choose_from_menu($options, "var2", $form->var2, "");
+ // choose_from_menu($options, "emailstudents", $form->emailstudents, "");
+ helpbutton("emailstudents", get_string("emailstudents", "assignment"), "assignment");
+ ?>
+ </td>
+</tr>
+
+</table>
+
+<center>
+<br />
+<input type="submit" value="<?php print_string("continue") ?>" />
+</center>
-rem\r
-rem Table structure for table chat\r
-rem\r
-\r
-drop TABLE prefix_chat;\r
-CREATE TABLE prefix_chat (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- name varchar2(255) default '' not null,\r
- intro varchar2(1024) NOT NULL,\r
- keepdays number(11) default '0' not null,\r
- studentlogs number(4) default '0' not null,\r
- chattime number(10) default '0' not null,\r
- schedule number(4) default '0' not null,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-\r
-COMMENT on table prefix_chat is 'Each of these is a chat room';\r
-\r
-drop sequence p_chat_seq;\r
-create sequence p_chat_seq;\r
-\r
-create or replace trigger p_chat_trig\r
- before insert on prefix_chat\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_chat_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(1,'name 1','intro 1',1,1,1,1,1);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(2,'name 2','intro 2',2,2,2,2,2);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(3,'name 3','intro 3',3,3,3,3,3);\r
-insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(4,'name 4','intro 4',4,4,4,4,4);\r
-\r
-select * from prefix_chat;\r
-\r
-rem --------------------------------------------------------\r
-rem\r
-rem Table structure for table chat_messages\r
-rem\r
-\r
-drop TABLE prefix_chat_messages;\r
-CREATE TABLE prefix_chat_messages (\r
- id number(10) primary key,\r
- chatid number(10) default '0' not null,\r
- userid number(10) default '0' not null,\r
- system number(1) default '0' not null,\r
- message varchar2(1024) NOT NULL,\r
- timestamp number(10) default '0' not null\r
-);\r
-\r
-COMMENT on table prefix_chat_messages is 'Stores all the actual chat messages';\r
-\r
-create index timemodifiedchat on prefix_chat_messages(timestamp,chatid);\r
-\r
-drop sequence p_chat_messages_seq;\r
-create sequence p_chat_messages_seq;\r
-\r
-create or replace trigger p_chat_messages_trig\r
- before insert on prefix_chat_messages\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_chat_messages_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(1,1,1,'message1',1);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(2,2,2,'message2',2);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(3,3,3,'message3',3);\r
-insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(4,4,4,'message4',4);\r
-\r
-select * from prefix_chat_messages;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table chat_users\r
-rem\r
-\r
-drop TABLE prefix_chat_users;\r
-CREATE TABLE prefix_chat_users (\r
- id number(10) primary key,\r
- chatid number(11) default '0' not null,\r
- userid number(11) default '0' not null,\r
- version varchar2(16) default '' not null,\r
- ip varchar2(15) default '' not null,\r
- firstping number(10) default '0' not null,\r
- lastping number(10) default '0' not null,\r
- lastmessageping number(10) default '0' not null,\r
- sid varchar2(32) default '' not null,\r
- course number(10) default '0' not null,\r
- lang varchar2(10) default '' not null\r
-);\r
-\r
-create index userid on prefix_chat_users(userid);\r
-create index lastping on prefix_chat_users(lastping);\r
-\r
-drop sequence p_chat_users_seq;\r
-create sequence p_chat_users_seq;\r
-\r
-create or replace trigger p_chat_users_trig\r
- before insert on prefix_chat_users\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_chat_users_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-COMMENT on table prefix_chat_users is 'Keeps track of which users are in which chat rooms';\r
-\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(1,1,'version1','ip1',1,1,1,'sid1');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(2,2,'version2','ip2',2,2,2,'sid2');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(3,3,'version3','ip3',3,3,3,'sid3');\r
-insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(4,4,'version4','ip4',4,4,4,'sid4');\r
-\r
-select * from prefix_chat_users;\r
-\r
-delete from prefix_log_display where module='chat';\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'view', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'add', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'update', 'chat', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'report', 'chat', 'name');\r
-\r
-select * from prefix_log_display where module='chat' order by 1,2,3,4;\r
+rem
+rem Table structure for table chat
+rem
+
+drop TABLE prefix_chat;
+CREATE TABLE prefix_chat (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ name varchar2(255) default '' not null,
+ intro varchar2(1024) NOT NULL,
+ keepdays number(11) default '0' not null,
+ studentlogs number(4) default '0' not null,
+ chattime number(10) default '0' not null,
+ schedule number(4) default '0' not null,
+ timemodified number(10) default '0' not null
+);
+
+
+COMMENT on table prefix_chat is 'Each of these is a chat room';
+
+drop sequence p_chat_seq;
+create sequence p_chat_seq;
+
+create or replace trigger p_chat_trig
+ before insert on prefix_chat
+ referencing new as new_row
+ for each row
+ begin
+ select p_chat_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(1,'name 1','intro 1',1,1,1,1,1);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(2,'name 2','intro 2',2,2,2,2,2);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(3,'name 3','intro 3',3,3,3,3,3);
+insert into prefix_chat(course,name,intro,keepdays,studentlogs,chattime,schedule,timemodified) values(4,'name 4','intro 4',4,4,4,4,4);
+
+select * from prefix_chat;
+
+rem --------------------------------------------------------
+rem
+rem Table structure for table chat_messages
+rem
+
+drop TABLE prefix_chat_messages;
+CREATE TABLE prefix_chat_messages (
+ id number(10) primary key,
+ chatid number(10) default '0' not null,
+ userid number(10) default '0' not null,
+ system number(1) default '0' not null,
+ message varchar2(1024) NOT NULL,
+ timestamp number(10) default '0' not null
+);
+
+COMMENT on table prefix_chat_messages is 'Stores all the actual chat messages';
+
+create index timemodifiedchat on prefix_chat_messages(timestamp,chatid);
+
+drop sequence p_chat_messages_seq;
+create sequence p_chat_messages_seq;
+
+create or replace trigger p_chat_messages_trig
+ before insert on prefix_chat_messages
+ referencing new as new_row
+ for each row
+ begin
+ select p_chat_messages_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(1,1,1,'message1',1);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(2,2,2,'message2',2);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(3,3,3,'message3',3);
+insert into prefix_chat_messages (chatid,userid,system,message,timestamp) values(4,4,4,'message4',4);
+
+select * from prefix_chat_messages;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table chat_users
+rem
+
+drop TABLE prefix_chat_users;
+CREATE TABLE prefix_chat_users (
+ id number(10) primary key,
+ chatid number(11) default '0' not null,
+ userid number(11) default '0' not null,
+ version varchar2(16) default '' not null,
+ ip varchar2(15) default '' not null,
+ firstping number(10) default '0' not null,
+ lastping number(10) default '0' not null,
+ lastmessageping number(10) default '0' not null,
+ sid varchar2(32) default '' not null,
+ course number(10) default '0' not null,
+ lang varchar2(10) default '' not null
+);
+
+create index userid on prefix_chat_users(userid);
+create index lastping on prefix_chat_users(lastping);
+
+drop sequence p_chat_users_seq;
+create sequence p_chat_users_seq;
+
+create or replace trigger p_chat_users_trig
+ before insert on prefix_chat_users
+ referencing new as new_row
+ for each row
+ begin
+ select p_chat_users_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+COMMENT on table prefix_chat_users is 'Keeps track of which users are in which chat rooms';
+
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(1,1,'version1','ip1',1,1,1,'sid1');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(2,2,'version2','ip2',2,2,2,'sid2');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(3,3,'version3','ip3',3,3,3,'sid3');
+insert into prefix_chat_users (chatid,userid,version,ip,firstping,lastping,lastmessageping,sid) values(4,4,'version4','ip4',4,4,4,'sid4');
+
+select * from prefix_chat_users;
+
+delete from prefix_log_display where module='chat';
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'view', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'add', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'update', 'chat', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('chat', 'report', 'chat', 'name');
+
+select * from prefix_log_display where module='chat' order by 1,2,3,4;
-<html>\r
-<body>\r
+<html>
+<body>
-<?php // $Id$\r
-\r
- $nomoodlecookie = true; // Session not needed!\r
-\r
- require('../../../config.php');\r
- require('../lib.php');\r
-\r
- $chat_sid = required_param('chat_sid', PARAM_ALPHANUM);\r
-\r
- if (!$chatuser = get_record('chat_users', 'sid', $chat_sid)) {\r
- error('Not logged in!');\r
- }\r
-\r
- chat_force_language($chatuser->lang);\r
-\r
- ob_start();\r
- ?>\r
-<script type="text/javascript">\r
-<!--\r
-\r
-scroll_active = true;\r
-function empty_field_and_submit() {\r
- var cf = document.getElementById('sendform');\r
- var inpf = document.getElementById('inputform');\r
- cf.chat_msgidnr.value = parseInt(cf.chat_msgidnr.value) + 1;\r
- cf.chat_message.value = inpf.chat_message.value;\r
- inpf.chat_message.value='';\r
- cf.submit();\r
- inpf.chat_message.focus();\r
- return false;\r
-}\r
-function prepareusers() {\r
- var frm = window.parent.frames;\r
- for(i = 0; i < frm.length; ++i) {\r
- if(frm[i].name == "users") {\r
- window.userFrame = frm[i];\r
- window.userHREF = frm[i].location.href;\r
- window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);\r
- }\r
- }\r
-}\r
-function reloadusers() {\r
- if(window.userFrame) {\r
- window.userFrame.location.href = window.userFrame.location.href;\r
- window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);\r
- }\r
-}\r
-// -->\r
-</script>\r
- <?php\r
-\r
- $meta = ob_get_clean();\r
- // TODO: there will be two onload in body tag, does it matter?\r
- print_header('', '', '', 'inputform.chat_message', $meta, false, ' ', '', false, 'onload="setfocus(); prepareusers();"');\r
-\r
-?>\r
-\r
- <form action="../empty.php" method="get" target="empty" id="inputform"\r
- onsubmit="return empty_field_and_submit();">\r
- >><input type="text" name="chat_message" size="60" value="" />\r
- <?php helpbutton("chatting", get_string("helpchatting", "chat"), "chat", true, false); ?>\r
- </form>\r
- \r
- <form action="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport/"; ?>" method="get" target="empty" id="sendform">\r
- <input type="hidden" name="win" value="message" />\r
- <input type="hidden" name="chat_message" value="" />\r
- <input type="hidden" name="chat_msgidnr" value="0" />\r
- <input type="hidden" name="chat_sid" value="<?php echo $chat_sid ?>" />\r
- </form>\r
-</body>\r
-\r
-</html>\r
+<?php // $Id$
+
+ $nomoodlecookie = true; // Session not needed!
+
+ require('../../../config.php');
+ require('../lib.php');
+
+ $chat_sid = required_param('chat_sid', PARAM_ALPHANUM);
+
+ if (!$chatuser = get_record('chat_users', 'sid', $chat_sid)) {
+ error('Not logged in!');
+ }
+
+ chat_force_language($chatuser->lang);
+
+ ob_start();
+ ?>
+<script type="text/javascript">
+<!--
+
+scroll_active = true;
+function empty_field_and_submit() {
+ var cf = document.getElementById('sendform');
+ var inpf = document.getElementById('inputform');
+ cf.chat_msgidnr.value = parseInt(cf.chat_msgidnr.value) + 1;
+ cf.chat_message.value = inpf.chat_message.value;
+ inpf.chat_message.value='';
+ cf.submit();
+ inpf.chat_message.focus();
+ return false;
+}
+function prepareusers() {
+ var frm = window.parent.frames;
+ for(i = 0; i < frm.length; ++i) {
+ if(frm[i].name == "users") {
+ window.userFrame = frm[i];
+ window.userHREF = frm[i].location.href;
+ window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);
+ }
+ }
+}
+function reloadusers() {
+ if(window.userFrame) {
+ window.userFrame.location.href = window.userFrame.location.href;
+ window.setTimeout("reloadusers();", <?php echo $CFG->chat_refresh_userlist; ?> * 1000);
+ }
+}
+// -->
+</script>
+ <?php
+
+ $meta = ob_get_clean();
+ // TODO: there will be two onload in body tag, does it matter?
+ print_header('', '', '', 'inputform.chat_message', $meta, false, ' ', '', false, 'onload="setfocus(); prepareusers();"');
+
+?>
+
+ <form action="../empty.php" method="get" target="empty" id="inputform"
+ onsubmit="return empty_field_and_submit();">
+ >><input type="text" name="chat_message" size="60" value="" />
+ <?php helpbutton("chatting", get_string("helpchatting", "chat"), "chat", true, false); ?>
+ </form>
+
+ <form action="<?php echo "http://$CFG->chat_serverhost:$CFG->chat_serverport/"; ?>" method="get" target="empty" id="sendform">
+ <input type="hidden" name="win" value="message" />
+ <input type="hidden" name="chat_message" value="" />
+ <input type="hidden" name="chat_msgidnr" value="0" />
+ <input type="hidden" name="chat_sid" value="<?php echo $chat_sid ?>" />
+ </form>
+</body>
+
+</html>
-rem\r
-rem Table structure for table choice\r
-rem\r
-\r
-drop TABLE prefix_choice;\r
-CREATE TABLE prefix_choice (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- name varchar2(255) default '' not null,\r
- text varchar2(1024) NOT NULL,\r
- format number(2) default '0' not null,\r
- answer1 varchar2(255) default 'Yes' not null,\r
- answer2 varchar2(255) default 'No' not null,\r
- answer3 varchar2(255) default NULL,\r
- answer4 varchar2(255) default NULL,\r
- answer5 varchar2(255) default NULL,\r
- answer6 varchar2(255) default NULL,\r
- publish number(2) default '0' not null,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-COMMENT on table prefix_choice is 'Available choices are stored here.';\r
-\r
-drop sequence p_choice_seq;\r
-create sequence p_choice_seq;\r
-\r
-create or replace trigger p_choice_trig\r
- before insert on prefix_choice\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_choice_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(1,'name1','text1',1,'1','1','1','1','1','1',1,1);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(2,'name2','text2',2,'2','2','2','2','2','2',2,2);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(3,'name3','text3',3,'3','3','3','3','3','3',3,3);\r
-insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(4,'name4','text4',4,'4','4','4','4','4','4',4,4);\r
-\r
-select * from prefix_choice order by 1,2;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table choice_answers\r
-rem\r
-\r
-drop TABLE prefix_choice_answers;\r
-CREATE TABLE prefix_choice_answers (\r
- id number(10) primary key,\r
- choice number(10) default '0' not null,\r
- userid number(10) default '0' not null,\r
- answer number(4) default '0' not null,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-comment on table prefix_choice_answers is 'Answers for each choice';\r
-\r
-drop sequence p_choice_answers_seq;\r
-create sequence p_choice_answers_seq;\r
-\r
-create or replace trigger p_choice_answers_trig\r
- before insert on prefix_choice_answers\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_choice_answers_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(1,1,1,1);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(2,2,2,2);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(3,3,3,3);\r
-insert into prefix_choice_answers (choice,userid,answer,timemodified) values(4,4,4,4);\r
-\r
-select * from prefix_choice_answers order by 1,2;\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-\r
-delete from prefix_log_display where module = 'choice';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'view', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'update', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'add', 'choice', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'report', 'choice', 'name');\r
-\r
- \r
-\r
-\r
+rem
+rem Table structure for table choice
+rem
+
+drop TABLE prefix_choice;
+CREATE TABLE prefix_choice (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ name varchar2(255) default '' not null,
+ text varchar2(1024) NOT NULL,
+ format number(2) default '0' not null,
+ answer1 varchar2(255) default 'Yes' not null,
+ answer2 varchar2(255) default 'No' not null,
+ answer3 varchar2(255) default NULL,
+ answer4 varchar2(255) default NULL,
+ answer5 varchar2(255) default NULL,
+ answer6 varchar2(255) default NULL,
+ publish number(2) default '0' not null,
+ timemodified number(10) default '0' not null
+);
+
+COMMENT on table prefix_choice is 'Available choices are stored here.';
+
+drop sequence p_choice_seq;
+create sequence p_choice_seq;
+
+create or replace trigger p_choice_trig
+ before insert on prefix_choice
+ referencing new as new_row
+ for each row
+ begin
+ select p_choice_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(1,'name1','text1',1,'1','1','1','1','1','1',1,1);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(2,'name2','text2',2,'2','2','2','2','2','2',2,2);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(3,'name3','text3',3,'3','3','3','3','3','3',3,3);
+insert into prefix_choice(course,name,text,format,answer1,answer2,answer3,answer4,answer5,answer6,publish,timemodified) values(4,'name4','text4',4,'4','4','4','4','4','4',4,4);
+
+select * from prefix_choice order by 1,2;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table choice_answers
+rem
+
+drop TABLE prefix_choice_answers;
+CREATE TABLE prefix_choice_answers (
+ id number(10) primary key,
+ choice number(10) default '0' not null,
+ userid number(10) default '0' not null,
+ answer number(4) default '0' not null,
+ timemodified number(10) default '0' not null
+);
+
+comment on table prefix_choice_answers is 'Answers for each choice';
+
+drop sequence p_choice_answers_seq;
+create sequence p_choice_answers_seq;
+
+create or replace trigger p_choice_answers_trig
+ before insert on prefix_choice_answers
+ referencing new as new_row
+ for each row
+ begin
+ select p_choice_answers_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(1,1,1,1);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(2,2,2,2);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(3,3,3,3);
+insert into prefix_choice_answers (choice,userid,answer,timemodified) values(4,4,4,4);
+
+select * from prefix_choice_answers order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'choice';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'view', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'update', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'add', 'choice', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('choice', 'report', 'choice', 'name');
+
+
+
+
-<div align="center">\r
-<table>\r
-<tr><td>Title: </td><td>[[title]]</td></tr>\r
-<tr><td>Caption: </td><td>[[caption]]</td></tr>\r
-</table>\r
-<hr>\r
-[[image]]\r
+<div align="center">
+<table>
+<tr><td>Title: </td><td>[[title]]</td></tr>
+<tr><td>Caption: </td><td>[[caption]]</td></tr>
+</table>
+<hr>
+[[image]]
</div>
\ No newline at end of file
-/****** List View CSS ******/\r
-\r
-#pictures {\r
- width: 750px;\r
-}\r
-\r
-.picture {\r
- padding: 5px;\r
- border-style: solid;\r
- border-width: thin;\r
- border-color: #779;\r
- background-color: white;\r
-\r
- display:table-cell;display:inline-table;display:inline-block;\r
-}\r
-\r
-.pictureframe {\r
- padding: 5px;\r
-\r
- display:table-cell;display:inline-table;display:inline-block;\r
-}\r
-\r
-.picturediv {\r
- display: inline;\r
- width: 150px;\r
- height: 200px;\r
-}\r
-\r
-.inline {\r
- display: inline;\r
-}\r
-\r
-/***** Single View CSS *****/\r
-\r
-.caption {\r
- font-style: italic;\r
-}\r
-\r
-#singleimage {\r
- width: 700px;\r
+/****** List View CSS ******/
+
+#pictures {
+ width: 750px;
+}
+
+.picture {
+ padding: 5px;
+ border-style: solid;
+ border-width: thin;
+ border-color: #779;
+ background-color: white;
+
+ display:table-cell;display:inline-table;display:inline-block;
+}
+
+.pictureframe {
+ padding: 5px;
+
+ display:table-cell;display:inline-table;display:inline-block;
+}
+
+.picturediv {
+ display: inline;
+ width: 150px;
+ height: 200px;
+}
+
+.inline {
+ display: inline;
+}
+
+/***** Single View CSS *****/
+
+.caption {
+ font-style: italic;
+}
+
+#singleimage {
+ width: 700px;
}
\ No newline at end of file
-var maxHeight = 550;\r
-var maxListHeight = 120;\r
-\r
-function init() {\r
- if (document.getElementById("singleimage")) single();\r
- /*else if (document.getElementById("pictures")) list();*/\r
-}\r
-\r
-function list() {\r
- imageDivs = document.getElementsByName("listimage");\r
- for (i=0; i < imageDivs.length; i++) {\r
- currentHeight = imageDivs[i].offsetHeight;\r
- currentWidth = imageDivs[i].offsetWidth;\r
- \r
- if (currentHeight > maxListHeight) {\r
- ratio = maxListHeight / currentHeight;\r
- imageDivs[i].style.width = (currentWidth*ratio) + 'px';\r
- imageDivs[i].style.height = (currentHeight*ratio) + 'px';\r
- imageDivs[i].firstChild.style.height = '100%';\r
- imageDivs[i].firstChild.style.width = '100%';\r
- }\r
- }\r
-}\r
-\r
-function single() {\r
- var imageDiv = document.getElementById("singleimage");\r
-\r
- if (imageDiv) {\r
- currentHeight = imageDiv.offsetHeight;\r
- currentWidth = imageDiv.offsetWidth;\r
- \r
- if (currentHeight > maxHeight) {\r
- ratio = maxHeight / currentHeight;\r
- imageDiv.style.width = (currentWidth*ratio) + 'px';\r
- imageDiv.style.height = (currentHeight*ratio) + 'px';\r
- \r
- }\r
- }\r
-}\r
-\r
+var maxHeight = 550;
+var maxListHeight = 120;
+
+function init() {
+ if (document.getElementById("singleimage")) single();
+ /*else if (document.getElementById("pictures")) list();*/
+}
+
+function list() {
+ imageDivs = document.getElementsByName("listimage");
+ for (i=0; i < imageDivs.length; i++) {
+ currentHeight = imageDivs[i].offsetHeight;
+ currentWidth = imageDivs[i].offsetWidth;
+
+ if (currentHeight > maxListHeight) {
+ ratio = maxListHeight / currentHeight;
+ imageDivs[i].style.width = (currentWidth*ratio) + 'px';
+ imageDivs[i].style.height = (currentHeight*ratio) + 'px';
+ imageDivs[i].firstChild.style.height = '100%';
+ imageDivs[i].firstChild.style.width = '100%';
+ }
+ }
+}
+
+function single() {
+ var imageDiv = document.getElementById("singleimage");
+
+ if (imageDiv) {
+ currentHeight = imageDiv.offsetHeight;
+ currentWidth = imageDiv.offsetWidth;
+
+ if (currentHeight > maxHeight) {
+ ratio = maxHeight / currentHeight;
+ imageDiv.style.width = (currentWidth*ratio) + 'px';
+ imageDiv.style.height = (currentHeight*ratio) + 'px';
+
+ }
+ }
+}
+
window.onload = init;
\ No newline at end of file
-<div class="picturediv">\r
-<table class="pictureframe"><tr><td>\r
-<table class="picture">\r
-<tr><td><div name="listimage">[[image]]</div></td></tr>\r
-<tr><td align="right">##edit## ##delete## ##approve##</td></tr>\r
-</table>\r
-</td></tr></table>\r
-</div>\r
+<div class="picturediv">
+<table class="pictureframe"><tr><td>
+<table class="picture">
+<tr><td><div name="listimage">[[image]]</div></td></tr>
+<tr><td align="right">##edit## ##delete## ##approve##</td></tr>
+</table>
+</td></tr></table>
+</div>
-<div align="center">\r
+<div align="center">
<div align="center" id="pictures">
\ No newline at end of file
-<div align="center">\r
-<table id="single">\r
-<tr><td align="center"><h3>[[title]]</h3></td></tr>\r
-<tr><td align="center"><div id="singleimage">[[image]]</div></td></tr>\r
-<tr><td align="center"><span class="caption">[[caption]]</span></td></tr>\r
-<tr><td align="center">##Edit## ##More## ##Delete## ##Approve##</td></tr>\r
-</table>\r
+<div align="center">
+<table id="single">
+<tr><td align="center"><h3>[[title]]</h3></td></tr>
+<tr><td align="center"><div id="singleimage">[[image]]</div></td></tr>
+<tr><td align="center"><span class="caption">[[caption]]</span></td></tr>
+<tr><td align="center">##Edit## ##More## ##Delete## ##Approve##</td></tr>
+</table>
</div>
\ No newline at end of file
INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('forum', 'subscribe', 'forum', 'name');
INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('forum', 'unsubscribe', 'forum', 'name');
-select * from prefix_log_display where module = 'forum';\r
+select * from prefix_log_display where module = 'forum';
-<!--\r
-// PLEASE NOTE that this version is more recent than the incorrectly \r
-// numbered v6.1, dated 2003.11.17. From now on, version numbers will \r
-// follow those of Hot Potatoes.\r
-/* hot-potatoes.js (v6.0.4.0 - 2005.02.18)\r
- * =======================================\r
- * by Gordon Bateson, February 2003\r
- * Copyright (c) 2003 Gordon Bateson. All Rights Reserved.\r
- *\r
- * You are hereby granted a royalty free license to use or modify this \r
- * software provided that this copyright notice appears on all copies. \r
- *\r
- * This software is provided "AS IS" without a warranty of any kind.\r
- * \r
- * Documentation and downloads may be available from: \r
- * http://www.kanazawa-gu.ac.jp/~gordon/research/hot-potatoes/\r
- */\r
-// This JavaScript library modifies the SendResults and StartUp functions \r
-// used by hotpot v5 and v6, so that more (or less!) details about the\r
-// student can be input, and more details of a quiz's questions and answers \r
-// can be submitted to the server when the quiz is finished\r
-// If the arrays below (Login, DB, JBC, ...) are set BEFORE calling this \r
-// script, they will NOT be overwritten. Any array that is not set, will \r
-// use the defaults below. This is useful if you want to use different \r
-// settings for different quizzes.\r
-// ************\r
-// Login Screen\r
-// ************\r
-if (window.Login==null) {\r
- Login = new Array();\r
- Login[0] = true; // Show prompt for user name\r
- // This can also be a string of user names ... \r
- // Login[0] = "Guest,Peter,Paul,Mary,Webmaster";\r
- // or an array of user names (and on-screen texts) (and passwords) ...\r
- // Login[0] = new Array("Guest", "001,Peter,xxxx", "002,Paul,yyyy", "003,Mary,zzzz", "Webmaster");\r
- // and can also be written as ...\r
- // Login[0] = new Array(\r
- // new Array("Guest"),\r
- // new Array("001", "Peter", "xxxx"),\r
- // new Array("002", "Paul", "yyyy"),\r
- // new Array("003", "Mary", "zzzz"),\r
- // new Array("Webmaster")\r
- // );\r
- Login[1] = true; // Show prompt for student's UserID\r
- // If there is no password prompt (i.e. Logon[3] is false), this value \r
- // will be checked against the password information, if any, in Login[0]\r
- Login[2] = false; // Show prompt for student's email\r
- Login[3] = false; // Show prompt for quiz password, and check this value against \r
- // the password information, if any, in Login[0]\r
- // This can also be a string required to start the quiz ...\r
- // Login[3] = "password";\r
- Login[4] = true; // Show prompt for the cookie expiry date\r
- // If false, cookies expire at the end of the current session\r
- Login[5] = "guest,webmaster"\r
- // guest user names (case insensitive) ... \r
- // Login[5] = "guest,webmaster"; \r
- // These users do NOT need to fill in other login fields\r
- // and their quiz results are NOT added to the database\r
- // the Login prompts and error messages \r
- // are defined in the MSG array (see below)\r
-}\r
-// *********\r
-// Database (for use with BFormMail)\r
-// *********\r
-if (window.DB==null) {\r
- DB = new Array();\r
- DB[0] = true; // append form fields to database on server\r
- // If you are NOT using BFormMail's database feature, \r
- // set DB[0]=false, and you can then safely ignore DB[1 to 5]\r
- DB[1] = "/home/gordon/public_html/cgi/hot-potatoes-data"; \r
- // append_db folder path (no trailing slash)\r
- // Can be either an absolute path e.g. "/home/gordon/public_html/cgi/hot-potatoes-data"\r
- // or a relative (to CGI bin) path e.g. "hot-potatoes-data"\r
- DB[2] = "hot-potatoes"; \r
- // append_db file name (no extension)\r
- // If left blank, the quiz file name, without extension, will be used\r
- // i.e. each quiz will have its results stored in a different file.\r
- // If filled in, this file will store the results for ALL quizzes.\r
- // Database files and folders must be set up BEFORE running the quiz \r
- // must have appropriate access privileges (on Unix, use "chmod 666").\r
- DB[3] = ""; // append_db extension (if left blank, ".txt" will be used)\r
- DB[4] = ""; // db_fields (if left blank, ALL quiz fields will be sent)\r
- DB[5] = ""; // db_delimiter (if left blank, tab will be used)\r
- DB[6] = "REMOTE_ADDR,HTTP_USER_AGENT"; \r
- // env_report ('REMOTE_ADDR','HTTP_USER_AGENT' and a few others)\r
- // for a complete description of these fields are, see ... \r
- // http://www.infosheet.com/stuff/BFormMail.readme\r
- // Switches DB[7] and DB[8] force the settings in the ResultForm\r
- // In v5 and v6 quizzes, these settings wil be override those in the original quiz\r
- // If the quiz results are to be sent to an LMS (via the "store" form)\r
- // then switches DB[7] and DB[8] are not used\r
- DB[7] = ''; // URL of form processing script\r
- // e.g. http://www.kanazawa-gu.ac.jp/~gordon/cgi/bformmail.cgi\r
- DB[8] = ''; // email address to which results should be sent\r
- // e.g. gordon@kanazawa-gu.ac.jp\r
-}\r
-// By default the quiz's question's scores will be returned. \r
-// If you want more detailed information, set the flags below:\r
-// ********\r
-// JBC\r
-// ********\r
-if (window.JBC==null) {\r
- JBC = new Array();\r
- JBC[0] = true; // show separator line between answers on email\r
- JBC[1] = true; // show number of attempts to answer question\r
- JBC[2] = true; // show question texts\r
- JBC[3] = true; // show right answer(s)\r
- JBC[4] = true; // show wrong answer(s)\r
- JBC[5] = true; // show ignored answer(s)\r
- JBC[6] = false; // show answer as text (false) or number (true)\r
-}\r
-// JBC quizzes use the global variables 'I' and 'Status'\r
-// I : an array of JBC_QUESTIONs (one for each question)\r
-// JBC_QUESTION :\r
-// [0] : question text\r
-// [1] : array of JBC_ANSWERs (one for each answer)\r
-// [2] : single/multi flag\r
-// 0 : single answer (using 'button')\r
-// 1 : multiple answers (using 'checkbox')\r
-// JBC_ANSWER :\r
-// [0] : answer text\r
-// [1] : answer feedback\r
-// [2] : correct answer flag\r
-// 0 : this is NOT the correct answer\r
-// 1 : this is the correct answer\r
-// Status : an array of JBC_QUESTION_STATUSes\r
-// JBC_QUESTION_STATUS:\r
-// [0] : correctly answered yet flag\r
-// 0 : this question has NOT been correctly answered\r
-// 1 : this question has been correctly answered\r
-// [1] : array of JBC_ANSWER_STATUSes (one for each answer)\r
-// '0' : initial value\r
-// 'R' : single answer question was answered 'R'ight\r
-// 'W' : single answer question was answered 'W'rong\r
-// 'C' : multiple answer question's checkbox was 'C'hecked\r
-// 'U' : multiple answer question's checkbox was 'U'nchecked\r
-// [2] : number of times this question has been wrongly answered\r
-// [3] : score (out of 1) for this question (maybe undefined on HP<5.5)\r
-// 0 : not correct yet\r
-// 0<[3]<1 : correct but only after [2] wrong attempts\r
-// 1 : correct first time (bravo!)\r
-// N.B. score = (numberOfAnswers - numberofWrongTries) / numberOfAnswers\r
-// ********\r
-// JCloze\r
-// ********\r
-if (window.JCloze==null) {\r
- JCloze = new Array();\r
- JCloze[0] = true; // show separator line between answers on email\r
- JCloze[1] = true; // show student's correct answer\r
- JCloze[2] = true; // show other correct answer(s), if any\r
- JCloze[3] = true; // show wrong answer(s), if any (NOT available for v5)\r
- JCloze[4] = false; // show number of hints + checks (legacy field, replaced by [7]+[9])\r
- JCloze[5] = false; // show if clue was asked for or not (legacy field, replaced by [8])\r
- JCloze[6] = true; // show clue\r
- JCloze[7] = true; // show number of hints (=next letter requests)\r
- JCloze[8] = true; // show number of clues\r
- JCloze[9] = true; // show number of checks\r
-}\r
-// JCloze quizzes use the global variables 'I' and 'State'\r
-// I : array of JCLOZE_ANSWERs\r
-// JCLOZE_ANSWER :\r
-// [0] : (unused)\r
-// [1] : array of JCLOZE_ANSWER_TEXTs\r
-// [2] : clue for this answer\r
-// JCLOZE_ANSWER_TEXT : \r
-// [0] : array (seems unnecessary, just the text would be enough?)\r
-// [0] : text of possible answer\r
-// State : array of JCLOZE_ANSWER_STATEs\r
-// JCLOZE_ANSWER_STATE (v5) : \r
-// [0] : clue asked for or not\r
-// [1] : number of hints (show next letter) and penalties ('check' an incorrect answer)\r
-// [2] : length of answer matched\r
-// [3] : score for this item\r
-// [4] : already answered correctly \r
-// [5] : answer entered in text box (right or not)\r
-// JCLOZE_ANSWER_STATE (v6)\r
-// this.ClueGiven = false;\r
-// this.HintsAndChecks = 0;\r
-// this.MatchedAnswerLength = 0;\r
-// this.ItemScore = 0;\r
-// this.AnsweredCorrectly = false;\r
-// this.Guesses = new Array(); last guess is correct answer\r
-// ********\r
-// JCross\r
-// ********\r
-if (window.JCross==null) {\r
- JCross = new Array();\r
- JCross[0] = true; // show separator line between answers on email\r
- JCross[1] = true; // show number of penalties (hints or checks before complete)\r
- JCross[2] = true; // show number of letters\r
- JCross[3] = true; // show correct answers\r
- JCross[4] = true; // show clues\r
- JCross[5] = true; // show wrong answers\r
- JCross[6] = true; // show if clue was asked for or not\r
- JCross[7] = true; // show number of hints (=next letter requests)\r
- JCross[8] = true; // show number of checks\r
- // there are no "ignored" answers for JCross quizzes\r
-}\r
-// JCross quizzes use the following global variables: \r
-// L : letters (of correct answers)\r
-// C : clue numbers (CL in v6)\r
-// G : guesses\r
-// 'L', 'C' ('CL') and 'G' are all 2-dimensional arrays (rows x cols)\r
-//\r
-// v5 quizzes additionally use the following single-dimension arrays\r
-// A : clues for across (horizontal) words \r
-// D : clues for down (vertical) words \r
-// N.B. form is only sent when all answers are correct so \r
-// you can't find out what 'wrong' answers were entered\r
-// ********\r
-// JMatch\r
-// ********\r
-if (window.JMatch==null) {\r
- JMatch = new Array();\r
- JMatch[0] = true; // show separator line between answers on email\r
- JMatch[1] = false; // show number of penalties (= total number of checks)\r
- JMatch[2] = true; // show LHS texts (the question)\r
- JMatch[3] = true; // show correct answers\r
- JMatch[4] = true; // show wrong answers\r
- JMatch[5] = true; // show checks (per match) [empty or unchanged RHS are not counted]\r
- // JMatch has no "clue" or "hint" buttons\r
- // there cannot be any "ignored" answers\r
-}\r
-// v5 JMatch quizzes use the global variables 'I' and 'Status' (and 'RItems')\r
-// v6 JMatch quizzes use only 'Status'\r
-// v6+ JMatch quizzes use 'F' and 'D' (see below)\r
-// I : an array of JMATCH_PAIRs (one for each pair)\r
-// JMATCH_PAIR :\r
-// [0] : LHS text\r
-// [1] : RHS text\r
-// [2] : fixed (=not jumbled) flag\r
-// 0 : not fixed\r
-// 1 : fixed\r
-// [3] : index in drop down list selection\r
-// Status : an array of JMATCH_PAIR_STATUSes\r
-// JMATCH_PAIR_STATUS:\r
-// [0] : correctly matched yet flag\r
-// 0 : this pair has NOT been correctly matched\r
-// 1 : this pair has been correctly matched\r
-// [1] : number of times this item has been wrongly matched\r
-// v6 quizzes only\r
-// [2] : id of original SELECT element containing possible matches\r
-// Note that after matching, this SELECT is removed, so don't try looking for it :-)\r
-// v6+ JMatch quizzes use the global variables 'F' and 'D'\r
-// F : array of JMATCH_FIXED_ITEMs\r
-// JMATCH_FIXED_ITEM:\r
-// [0] : text\r
-// [1] : tag\r
-// D : array of JMATCH_DRAGGABLE_ITEMs\r
-// JMATCH_DRAGGABLE_ITEM\r
-// [0] : text\r
-// [1] : tag of the F item to which it SHOULD be dragged\r
-// [2] : tag of the F item to which it was dragged (initally 0)\r
-// N.B. form is only sent when all answers are correct so \r
-// you can't find out what 'wrong' answers were entered\r
-// ********\r
-// JMix\r
-// ********\r
-if (window.JMix==null) {\r
- JMix = new Array();\r
- JMix[0] = true; // show separator line between answers on email\r
- JMix[1] = false; // show number of wrong guesses (replaced by JMix[5])\r
- JMix[2] = true; // show right answer\r
- JMix[3] = true; // show wrong answer, if any\r
- JMix[4] = false; // show answer as text (false) or number (true)\r
- JMix[5] = true; // show number of checks\r
- JMix[6] = true; // show number of hints (=show next word)\r
-}\r
-// JMix quizzes use the global variables \r
-// 'Segments', 'GuessSequence' and 'Penalties' \r
-// Segments : array of JMix_QUESTIONs\r
-// JMix_QUESTION:\r
-// [0] : text\r
-// [1] : order in sequence\r
-// [2] : used flag\r
-// GuessSequence : array of 'order in sequence' numbers\r
-// Penalties : number of incorrect guesses\r
-// ********\r
-// JQuiz\r
-// ********\r
-if (window.JQuiz==null) {\r
- JQuiz = new Array();\r
- JQuiz[0] = true; // show separator line between answers on email\r
- JQuiz[1] = true; // show question text\r
- JQuiz[2] = true; // show student's correct answer(s)\r
- JQuiz[3] = false; // show wrong and ignored answer(s) (legacy field superceded by [8] & [9])\r
- JQuiz[4] = true; // show number of hints requested\r
- JQuiz[5] = false; // show number of checks of incorrect answers (legacy field superceded by [12])\r
- // HP6 v6 quizzes only\r
- JQuiz[6] = false; // show answer value (false) or A,B,C... index (true)\r
- JQuiz[7] = true; // show all students answers\r
- JQuiz[8] = true; // show student's wrong answers\r
- JQuiz[9] = true; // show ignored answers (not relevant for multi-select questions)\r
- JQuiz[10] = true; // show score weightings\r
- JQuiz[11] = true; // show question type\r
- JQuiz[12] = true; // show number of checks (if true, then JQuiz[5] of will be ignored)\r
- JQuiz[13] = true; // show number of times ShowAnswer button was pressed (usually 0 or 1)\r
-}\r
-// v5 JQuiz quizzes use the global variables 'I' and 'Status'\r
-// I : array of JQUIZ_ANSWERs\r
-// JQUIZ_ANSWER :\r
-// [0] : question text\r
-// [1] : array of JQUIZ_ANSWER_TEXTs (one for each answer)\r
-// JQUIZ_ANSWER_TEXT :\r
-// [0] : array (seems unnecessary, just the text would be enough?)\r
-// [0] : text of possible answer\r
-// Status : array of JQUIZ_ANSWER_STATEs\r
-// JQUIZ_ANSWER_STATE : \r
-// [0] : question done or not\r
-// [1] : number of wrong checks\r
-// [2] : number of hints asked for\r
-// [3] : student's answer\r
-// [4] : score for this question\r
-// v6 JQuiz quizzes use the global variables 'I' and 'State'\r
-// I : array of JQUIZ_QUESTIONs\r
-// JQUIZ_QUESTION :\r
-// [0] : weighting\r
-// [1] : ?? (always set to '')\r
-// [2] : question type\r
-// '0'=multiple-choice, '1'=short-answer, '2'=hybrid, '3'=multi-select\r
-// [3] : array of JQUIZ_ANSWERSs (one for each possible answer)\r
-// JQUIZ_ANSWER :\r
-// [0] : answer value\r
-// [1] : feedback text\r
-// [2] : correct answer flag (1=a correct answer, 0=a wrong answer)\r
-// [3] : weighted score (as percentage) if correct\r
-// [4] : flag (usually set to 1, but for hybrid answers that are not \r
-// to be included in multiple choice options, it is set to 0)\r
-// State : array of JQUIZ_QUESTION_STATEs\r
-// JQUIZ_QUESTION_STATE : \r
-// [0] : score (-1 shows not done yet)\r
-// [1] : array showing on which number try each JQUIZ_ANSWER was selected\r
-// [2] : number of attempts at this question\r
-// [3] : total of weighted scores of correct answers that were selected\r
-// i.e. each time a correct answer is selected, \r
-// its JQUIZ_ANSWER[3] weighting is added to this total\r
-// so when all the correct answers have been selected, this will be 100\r
-// [4] : penalties incurred for hints (score is set to zero if >= 1)\r
-// [5] : - for multiple choice, short-answer and hybrid questions, this is a\r
-// comma-delimited list showing order in which answers were chosen\r
-// - for multi-select fields, this is bar-delimted ('|') list of settings \r
-// showing whether each checkbox was selected ('Y') on not ('N') when the \r
-// 'Check' button was clicked. The final item in the list will be the \r
-// settings for the correct answer.\r
-// N.B. JBC, JMatch(v5) and JQuiz(v5) all use global variables 'I' and 'Status'\r
-// JBC : I[0].length==3 && !window.RItems\r
-// JQuiz(v5) : I[0].length==2\r
-// JMatch(v5) : I[0].length==4 && window.RItems\r
-// N.B. JCloze(v5+6) and JQuiz(v6) both use global variables 'I' and 'State'\r
-// JCloze (v5) : I[0].length==3 && State[0].Guesses==null\r
-// JCloze (v6) : I[0].length==3 && State[0].Guesses!=null\r
-// JQuiz (v6) : I[0].length==4\r
-// **********\r
-// Rhubarb\r
-// **********\r
-if (window.Rhubarb==null) {\r
- Rhubarb = new Array();\r
- Rhubarb[0] = true; // show correct words (so far)\r
- Rhubarb[1] = true; // show correct words as count (true) or list (false)\r
- Rhubarb[2] = true; // show wrong words\r
- Rhubarb[3] = false; // show wrong words as count (true) or list (false)\r
- Rhubarb[4] = false; // show ignored words (not implemented yet)\r
- Rhubarb[5] = true; // show hints\r
-}\r
-// **********\r
-// Sequitur\r
-// **********\r
-if (window.Sequitur==null) {\r
- Sequitur = new Array();\r
- Sequitur[0] = true; // show count of correct button clicks\r
- Sequitur[1] = true; // show count of wrong button clicks\r
-}\r
-// **********\r
-// Messages\r
-// **********\r
-if (window.MSG==null) {\r
- MSG = new Array();\r
- // Login prompts\r
- MSG[0] = 'Name';\r
- MSG[1] = 'ID';\r
- MSG[2] = 'Email';\r
- MSG[3] = 'Password';\r
- MSG[4] = 'Cookies';\r
- // Login buttons\r
- MSG[5] = 'Start the Quiz';\r
- MSG[6] = 'Cancel';\r
- // Cookie menu options (only used if Login[4] is true)\r
- MSG[7] = 'keep for this session only';\r
- MSG[8] = 'keep for one day';\r
- MSG[9] = 'keep for one month';\r
- MSG[10] = 'do NOT keep cookies';\r
- // Login error messages\r
- MSG[11] = 'Sorry, you were unable to login. Please try again later.';\r
- MSG[12] = 'Please fill in all the information.';\r
- MSG[13] = 'Incorrect Password. Please try again.';\r
- MSG[14] = 'Incorrect ID. Please try again.';\r
- MSG[15] = 'Email address does not appear to be valid.';\r
- // day and month names (used in Start_Time and End_Time)\r
- MSG[16] = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');\r
- MSG[17] = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');\r
- // enable popups\r
- MSG[18] = 'Please enable pop-up windows on your browser.';\r
- // browser specific instuctions on how to enable popup windows\r
- var n = navigator;\r
- var s = n.userAgent.toLowerCase();\r
- if (n.appName=='Netscape' && s.indexOf('gecko')>=0) {\r
- // Netscape 6 and 7\r
- MSG[18] += '\n\n' + 'Edit->Preferences, ' + (s.indexOf('mac')>=0 ? 'Advanced->Scripts & Plugins' : 'Privacy & Security->Popup Window Controls');\r
- } else if (s.indexOf('safari')>=0) {\r
- // Safari\r
- MSG[18] += '\n\n' + 'on Safari menu, uncheck "Block Pop-Up Windows"';\r
- } else if (s.indexOf('firebird')>=0) {\r
- // Firebird\r
- MSG[18] += '\n\n' + 'Preferences->Web Features, uncheck "Block Pop-Up Windows"';\r
- } else if (s.indexOf('msie 6')>=0) {\r
- // IE 6 (WinXP.SP2)\r
- MSG[18] += '\n\n' + 'Tools->Pop-up Blocker->Turn Off Pop-up Blocker';\r
- }\r
-}\r
-//if (window.FEEDBACK==null) {\r
-// FEEDBACK = new Array();\r
-// FEEDBACK[0] = ''; // url of feedback page/script\r
-// FEEDBACK[1] = ''; // array of array('teachername', 'value');\r
-// FEEDBACK[2] = ''; // 'student name' [formmail only]\r
-// FEEDBACK[3] = ''; // 'email@somewhere.com>' [formmail only]\r
-// FEEDBACK[4] = ''; // window width\r
-// FEEDBACK[5] = ''; // window height\r
-// FEEDBACK[6] = ''; // 'Send a message to teacher' [prompt/button text]\r
-// FEEDBACK[7] = ''; // 'Title'\r
-// FEEDBACK[8] = ''; // 'Teacher'\r
-// FEEDBACK[8] = ''; // 'Message'\r
-// FEEDBACK[10] = ''; // 'Close this window' [formmail only]\r
-//}\r
-// **********\r
-// HP array\r
-// **********\r
-HP = new Array();\r
-for (var i=0; i<=8; i++) {\r
- HP[i] = new Array();\r
-}\r
-// indexes for the HP array (makes the code further down easier to read)\r
-_score = 0;\r
-_weight = 1;\r
-_correct = 2;\r
-_wrong = 3;\r
-_unused = 4;\r
-_hints = 5;\r
-_clues = 6;\r
-_checks = 7;\r
-_guesses = 8;\r
-// *************\r
-// Server Fields\r
-// *************\r
-if (window.ServerFields==null) {\r
- ServerFields = new Array();\r
- // these fields will be added to the ResultForm and submitted to the CGI script on the server.\r
- // 'Sort', 'return_link_title', 'return_link_url' and 'print_blank_fields' are useful for formmail\r
- // override the HP setting of sort fields (forces ALL fields to be displayed)\r
- ServerFields[0] = new Array('sort', '');\r
- // add link to close pop-up results window\r
- ServerFields[1] = new Array('return_link_title', 'Close this window');\r
- ServerFields[2] = new Array('return_link_url', 'javascript:self.close()');\r
- // make sure zero values are printed\r
- ServerFields[3] = new Array('print_blank_fields', 'yes');\r
- // you can also set other fields for your customized CGI script\r
- // e.g. adding a server defined start time (instead of a client defined start time)\r
- // ServerFields[4] = new Array('serverStartTime', '<?php echo date("Y-m-d H:i:s") ?>');\r
-}\r
-// *********************\r
-// Login screen\r
-// (not required by LMS)\r
-// *********************\r
-function QuizLogin(LoginPrompt) {\r
- if (!is_LMS() && (Login[0] || Login[1] || Login[2] || Login[3])) {\r
- var html = ''\r
- + '<html>'\r
- + '<head></head>'\r
- + '<body bgColor="#cccccc" onLoad="opener.setFocus(self)">'\r
- + '<form onSubmit="'\r
- + 'self.ok=true;'\r
- + 'self.expiry=null;'\r
- ;\r
- if (Login[4]) { // cookie expiry\r
- html += "opener.checkOK(self,'CookieExpiry');";\r
- }\r
- if (Login[0]) { // user name\r
- html += "opener.checkOK(self,'UserName');";\r
- }\r
- if (Login[1]) { // user ID\r
- html += "opener.checkOK(self,'UserID');";\r
- }\r
- if (Login[2]) { // user email\r
- html += "opener.checkOK(self,'UserEmail');";\r
- }\r
- if (Login[3]) { // quiz password\r
- html += "opener.checkOK(self,'Password');";\r
- }\r
- html += 'if(ok){'\r
- + 'opener.StartQuiz();'\r
- + 'self.close();'\r
- + '}else{'\r
- + 'if(isNaN(self.tries))self.tries=0;'\r
- + 'self.tries++;'\r
- + 'if(self.tries<3){'\r
- + 'opener.setFocus(self);'\r
- + '}else{'\r
- + "alert(opener.MSG[11]);"\r
- + 'opener.goBack();'\r
- + 'self.close();'\r
- + '}'\r
- + '}'\r
- + 'return false;'\r
- + '">'\r
- ;\r
- html += '<table>'\r
- + '<caption>' + LoginPrompt + '</caption>';\r
- ;\r
- if (Login[0]) { // user name\r
- var v = getCookie(self, 'UserName');\r
- html += '<tr>'\r
- + '<th align=right nowrap>' + MSG[0] + ' :</th>'\r
- + '<td>'\r
- ;\r
- if (typeof(Login[0])=='boolean') { // text box\r
- html += '<input type=text name=UserName value="' + v + '">';\r
- } else { // drop down menu of names\r
- // pattern to match commas and white space\r
- var comma = (window.RegExp) ? new RegExp('\\s*,\\s*') : ',';\r
- // convert list of names to array, if necessary\r
- if (typeof(Login[0])=='string') {\r
- Login[0] = Login[0].split(comma);\r
- }\r
- html += '<select name=UserName size=1>'\r
- + '<option value=""></option>'\r
- ;\r
- for(var i=0; i<Login[0].length; i++) {\r
- // convert name details to array if nececount_cary\r
- if (typeof(Login[0][i])=='string') {\r
- Login[0][i] = Login[0][i].split(comma);\r
- }\r
- html += makeOption(Login[0][i][0], v, Login[0][i][1]);\r
- }\r
- html += '</select>';\r
- }\r
- html += '</td>'\r
- + '</tr>'\r
- ;\r
- }\r
- if (Login[1]) { // user ID\r
- var v = getCookie(self, 'UserID');\r
- html += '<tr><th align=right nowrap>' + MSG[1] + ' :</th><td><input type=text name=UserID value="' + v + '"></td></tr>';\r
- }\r
- if (Login[2]) { // user email\r
- var v = getCookie(self, 'UserEmail');\r
- html += '<tr><th align=right nowrap>' + MSG[2] +' :</th><td><input type=text name=UserEmail value="' + v + '"></td></tr>';\r
- }\r
- if (Login[3]) { // quiz password\r
- var v = getCookie(self, 'Password');\r
- html += '<tr><th align=right nowrap>' + MSG[3] + ' :</th><td><input type=password name=Password value="' + v + '"></td></tr>';\r
- }\r
- if (Login[4]) { // cookie lifespan\r
- var v = getCookie(self, 'CookieExpiry');\r
- html += '<tr>'\r
- + '<th align=right nowrap>' + MSG[4] + ' :</th>'\r
- + '<td>'\r
- + '<select name="CookieExpiry" size=1>'\r
- + makeOption('session', v, MSG[7])\r
- + makeOption('day', v, MSG[8])\r
- + makeOption('month', v, MSG[9])\r
- + makeOption('never', v, MSG[10])\r
- + '</select>'\r
- + '</td>'\r
- + '</tr>'\r
- ;\r
- }\r
- html += '<tr>'\r
- + '<th> </th>'\r
- + '<td nowrap>'\r
- + '<input type=submit value="' + MSG[5] + '"> '\r
- + '<input type=button value="' + MSG[6] + '" onClick="opener.goBack();self.close();">'\r
- + '</td>'\r
- + '</tr>'\r
- + '</table></form></body></html>'\r
- ;\r
- // set height of Login Window\r
- var m = navigator.userAgent.indexOf('Mac')>=0;\r
- var h = (m ? 80 : 100);\r
- for (var i=0; i<5; i++) h += (Login[i] ? (m ? 20 : 25) : 0);\r
- // open up a new window\r
- if (!openWindow('', '', (m ? 320 : 300), h, 'RESIZABLE', html)) {\r
- alert(MSG[18]); // unable to open popup window\r
- }\r
- } else { // no Login required\r
- window.UserName = window.UserID = window.UserEmail = window.Password = '';\r
- window.StartQuiz();\r
- }\r
- return true;\r
-}\r
-function makeOption(value, v, txt) {\r
- return '<option value="' + value + '"' + (value==v ? ' SELECTED' : '') + '>' + (txt ? txt : value) + '</option>';\r
-}\r
-function setFocus(w) {\r
- w.focus(); // bring window to the front\r
- var obj = w.document.forms[0].elements;\r
- for(var i=0; i<obj.length; i++) {\r
- var v = getValue(w, i);\r
- if (v=='' || obj[i].type=='submit') {\r
- obj[i].focus();\r
- break;\r
- }\r
- }\r
-}\r
-function checkOK(w, n){\r
- var v = getValue(w, n, true);\r
- if (v || (n!='UserName' && isGuest())) {\r
- if (n=='CookieExpiry') setCookieExpiry(w, v);\r
- setCookie(self, n, v, w.expiry);\r
- if (n!='CookieExpiry') eval('self.' + n + '=v');\r
- } else {\r
- if (w.ok) alert(MSG[12]);\r
- w.ok = false;\r
- }\r
-}\r
-function getValue(w, n, flag) {\r
- var obj = w.document.forms[0].elements[n];\r
- var TYPE = obj.type.toUpperCase(); // required for ns4 (win)\r
- if (obj.options && TYPE.indexOf('SELECT')>=0){ \r
- var v = obj.options[obj.selectedIndex].value;\r
- } else {\r
- var v = obj.value;\r
- }\r
- if (flag) {\r
- var msg = '';\r
- if (n=='Password' || (n=='UserID' && !Login[3])) {\r
- var pwd = getPassword(w);\r
- if (pwd && v!=pwd) msg = MSG[n=='Password' ? 13 : 14];\r
- } \r
- if (n=='UserEmail' && window.RegExp) {\r
- var r = '(\\w|-)+';\r
- r = r + '(\\.' + r + ')';\r
- r = new RegExp('^(' + r + '*)@(' + r + '+)$');\r
- if (v.match(r)==null) msg = MSG[15];\r
- }\r
- if (msg) {\r
- obj.value = v = '';\r
- if (w.ok) alert(msg);\r
- w.ok = false;\r
- }\r
- }\r
- return v;\r
-}\r
-function getPassword(w) {\r
- var pwd = '';\r
- if (Login[3] && typeof(Login[3])=='string') {\r
- pwd = Login[3];\r
- } else if ((Login[3] || Login[1]) && typeof(Login[0])=='object') {\r
- var username = getValue(w, 'UserName');\r
- for(var i=0; i<Login[0].length; i++) {\r
- if (username==Login[0][i][0]) {\r
- pwd = Login[0][i][2];\r
- break;\r
- }\r
- }\r
- }\r
- return pwd;\r
-}\r
-function setCookieExpiry(w, v) {\r
- if (v=='never'){\r
- w.expiry = new Date('Thu, 01-Jan-70 00:00:01 GMT');\r
- } else if (v=='day' || v=='month') {\r
- var ms = (v=='month' ? 31 : 1) * 60 * 60 * 24 * 1000;\r
- w.expiry = new Date((new Date()).getTime() + ms);\r
- }\r
-}\r
-function setCookie(w, name, value, expires, path, domain, secure) {\r
- if (name) w.document.cookie = ''\r
- + 'HP_' + name + "=" + escape(value)\r
- + (expires ? "; expires=" + expires.toGMTString() : "")\r
- + (path ? "; path=" + path : "")\r
- + (domain ? "; domain=" + domain : "")\r
- + (secure ? "; secure" : "")\r
- ;\r
-}\r
-function getCookie(w, n) {\r
- var c = w.document.cookie;\r
- var i = c.indexOf('HP_' + n + '=');\r
- var j = (i<0) ? -1 : c.indexOf(';', (i += n.length + 4));\r
- return (i<0) ? '' : unescape(c.substring(i, ((j<0) ? c.length : j)));\r
-}\r
-function goBack(w) {\r
- if (w==null) w = self; // default\r
- if (w.history.length) w.history.back();\r
-}\r
-function openWindow(url, name, width, height, attributes, html) {\r
- // set height, width and attributes\r
- if (window.screen && width && height) {\r
- var W = screen.availWidth;\r
- var H = screen.availHeight;\r
- width = Math.min(width, W);\r
- height = Math.min(height, H);\r
- attributes = ''\r
- + (attributes ? (attributes+',') : '')\r
- + 'WIDTH='+width+',HEIGHT='+height\r
- ;\r
- }\r
- // create global hpWindows object, if necessary\r
- if (!window.hpWindows) window.hpWindows = new Array();\r
- // initialize window object\r
- var w = null;\r
- // has a window with this name been opened before?\r
- if (name && hpWindows[name]) {\r
- // http://www.webreference.com/js/tutorial1/exist.html\r
- if (hpWindows[name].open && !hpWindows[name].closed) {\r
- w = hpWindows[name];\r
- w.focus();\r
- } else {\r
- hpWindows[name] = null;\r
- }\r
- }\r
- // check window is not already open\r
- if (w==null) {\r
- // workaround for "Access is denied" errors in IE when offline\r
- // based on an idea seen at http://www.devshed.com/Client_Side/JavaScript/Mini_FAQ\r
- var ie_offline = (document.all && location.protocol=='file:');\r
- // try and open the new window\r
- w = window.open((ie_offline ? '' : url), name, attributes);\r
- // check window opened OK (user may have prevented popups)\r
- if (w) {\r
- // center the window\r
- if (window.screen && width && height) {\r
- w.moveTo((W-width)/2, (H-height)/2);\r
- }\r
- // add content, if required\r
- if (html) {\r
- with (w.document) {\r
- clear();\r
- open();\r
- write(html);\r
- close();\r
- }\r
- } else if (url && ie_offline) {\r
- w.location = url;\r
- }\r
- if (name) hpWindows[name] = w;\r
- }\r
- }\r
- return w;\r
-}\r
-// *********************\r
-// Send results by email\r
-// (not required by LMS)\r
-// *********************\r
-function SendAllResults(Score) {\r
- // check this quiz is not generated by a LMS\r
- if (!is_LMS()) {\r
- // add flat file database details to the results form\r
- AddDatabaseDetailsToResultForm();\r
- // add student details to the results form\r
- AddStudentDetailsToResultForm();\r
- // add question details to the results form\r
- AddQuestionDetailsToResultForm();\r
- // add server fields, if any, to results form\r
- AddServerFieldsToResultForm();\r
- // change "method" of form, because "get" only allows 512 byts of data\r
- ResultForm = replaceLast('method="get"', 'method="post"', ResultForm);\r
- // create results window and form\r
- var w = openWindow('', '', 500, 400, 'RESIZABLE,SCROLLBARS,LOCATION', ResultForm);\r
- // check window opened OK (user may have prevented popups)\r
- if (w) {\r
- // get shortcut to form object\r
- var form = w.document.forms[0];\r
- // update some important field values\r
- form.Score.value = Score + '%';\r
- form.realname.value = UserName;\r
- form.Start_Time.value = getTime(Start_Time);\r
- form.End_Time.value = getTime();\r
- // force email subject and Exercise title\r
- form.subject.value = document.title;\r
- form. Exercise.value = document.title;\r
- // update DB fields, if required\r
- if (DB[0] && !isGuest()) set_db_fields(form);\r
- if (DB[7]) form.action = DB[7];\r
- if (DB[8]) form.recipient.value = DB[8];\r
- // if this is a Netscape browser, check if the referer will be set OK\r
- if (navigator.appName=='Netscape' && (location.protocol=='file:' || navigator.userAgent.indexOf('Netscape6')>=0)) {\r
- // ns4 and ns7 set referer to 'file:// ...' when running a quiz offline\r
- // ns6.2 (at least) always sets referer to 'about:blank' \r
- // Netscape's setting of referer can cause BFormMail\r
- // to reject the form, so encode the form data as a URL\r
- var url = form.action;\r
- var obj = form.elements;\r
- for (var i=0; i<obj.length; i++) {\r
- var v = escape(obj[i].value);\r
- v = v.replace((new RegExp('\\+', 'g')), '%2B');\r
- url += (i==0 ? '?' : '&') + obj[i].name + '=' + v;\r
- }\r
- w.location.href = url;\r
- } else { // browser can POST form ok\r
- form.submit();\r
- }\r
- } else { // unable to open popup window\r
- alert(MSG[18]);\r
- }\r
- } // end if LMS\r
-}\r
-function isGuest() {\r
- // check username is not a "guest" user\r
- var flag = false;\r
- var n = getCookie(self, 'UserName').toLowerCase();\r
- if (n) {\r
- // convert list of user names to array, if necessary\r
- if(typeof(Login[5])=='string') {\r
- Login[5] = Login[5].split(',');\r
- }\r
- for(var i=0; i<Login[5].length; i++) {\r
- if (n==Login[5][i].toLowerCase()) {\r
- flag = true;\r
- break;\r
- }\r
- }\r
- }\r
- return flag;\r
-}\r
-function set_db_fields(form) {\r
- // update list of DB fields, if required\r
- if (DB[4]=='' && window.RegExp) {\r
- // add administration fields\r
- var db_fields = ''\r
- + 'subject,realname'\r
- + (Login[1] ? ',ID' : '')\r
- + (Login[2] ? ',email' : '')\r
- + (Login[3] ? ',password' : '')\r
- + ',Score,Start_Time,End_Time'\r
- ;\r
- // add answer fields (except separators)\r
- var r = new RegExp('^[^_]+_q\\d\\d_\\w+$');\r
- for(var i=0; i<form.elements.length; i++) {\r
- var n = form.elements[i].name;\r
- if (r.test(n)) db_fields += ',' + n;\r
- }\r
- form.db_fields.value = db_fields;\r
- }\r
- // make sure delimiter is set (NS6+ requires this be set here, not any earlier)\r
- form.db_delimiter.value = (DB[5] ? DB[5] : '\t');\r
-}\r
-function AddStudentDetailsToResultForm() {\r
- var sDetails = '';\r
- if (Login[0]) { // user name\r
- // use 'realname' instead of a separate 'Name' field\r
- // sDetails += hpHiddenField('Name', window.UserName);\r
- }\r
- if (Login[1]) { // user ID\r
- sDetails += hpHiddenField('ID', window.UserID);\r
- }\r
- if (Login[2]) { // user email\r
- sDetails += hpHiddenField('email', window.UserEmail);\r
- }\r
- if (sDetails && window.RegExp) {\r
- // insert sDetails before '<input...Score...></input>'\r
- var r = new RegExp('<input[^>]*Score[^>]*><\\/input>', 'i');\r
- var m = r.exec(ResultForm);\r
- if (m) {\r
- ResultForm = ResultForm.replace(m[0], sDetails + m[0] + makeSeparator('Time_'));\r
- sDetails = '';\r
- }\r
- }\r
- if (Login[3]) { // quiz password\r
- sDetails += hpHiddenField('Password', window.Password);\r
- ResultForm = replaceLast('</form>', sDetails + '</form>', ResultForm);\r
- }\r
-}\r
-function AddQuestionDetailsToResultForm() {\r
- var qDetails = GetQuestionDetails();\r
- if (qDetails) {\r
- // insert qDetails before the final </form> tag in the ResultForm\r
- ResultForm = replaceLast('</form>', qDetails + '</form>', ResultForm);\r
- }\r
-}\r
-function AddDatabaseDetailsToResultForm() {\r
- if (window.DB && DB[0] && !isGuest()) {\r
- var dbDetails = '';\r
- var folder = DB[1];\r
- if (folder && folder.charAt(folder.length-1)!='/') folder += '/';\r
- var file = DB[2];\r
- if (file=='') {\r
- file = location.href;\r
- file= file.substring(file.lastIndexOf('/')+1);\r
- var i = file.indexOf('?');\r
- if (i >= 0) file = file.substring(0, i);\r
- var i = file.lastIndexOf('.');\r
- if (i >= 0) file = file.substring(0, i);\r
- }\r
- var ext = (DB[3] ? DB[3] : 'txt');\r
- if (ext.charAt(0)!='.') ext = '.' + ext;\r
- dbDetails += hpHiddenField('append_db', folder + file + ext);\r
- dbDetails += hpHiddenField('db_fields', DB[4]);\r
- dbDetails += hpHiddenField('db_delimiter', ''); // NS6+ requires this be set later\r
- if (DB[6]) dbDetails += hpHiddenField('env_report', DB[6]);\r
- // insert dbDetails before the final </form> tag in the ResultForm\r
- ResultForm = replaceLast('</form>', dbDetails + '</form>', ResultForm);\r
- }\r
-}\r
-function AddServerFieldsToResultForm() {\r
- if (window.ServerFields) {\r
- var s = ''; // input tags for s(erver fields)\r
- for (var i=0; i<ServerFields.length; i++) {\r
- if (ServerFields[i][0] && window.RegExp) {\r
- // remove previous field value, if any\r
- var r = new RegExp('<input[^>]*name\\s*=\\s*["\']\\s*' + ServerFields[i][0] + '[^>]*>(\\s*<\\/input>)?', 'i');\r
- if (r.test(ResultForm)) {\r
- ResultForm = ResultForm.replace(r, '');\r
- }\r
- }\r
- if (ServerFields[i][1]) {\r
- s += hpHiddenField(ServerFields[i][0], ServerFields[i][1]);\r
- }\r
- } // end for\r
- if (s) ResultForm = replaceLast('</form>', s + '</form>', ResultForm);\r
- }\r
-}\r
-function replaceLast(a, b, c) {\r
- // replace last occurrence of 'a' in 'c' with 'b'\r
- var l = a.length;\r
- var i = c.lastIndexOf(a);\r
- return (i<0 || l==0) ? c : (c.substring(0, i) + b + c.substring(i+l));\r
-}\r
-// *************************\r
-// Extract question details\r
-// *************************\r
-function GetQuestionDetails() {\r
- var hp = hpVersion();\r
- var t = hpQuizType();\r
- var v = hpQuizVersion();\r
- return (t==1) ? GetJbcQuestionDetails(hp, v) : \r
- (t==2) ? GetJClozeQuestionDetails(hp, v) : \r
- (t==3) ? GetJCrossQuestionDetails(hp, v) : \r
- (t==4) ? GetJMatchQuestionDetails(hp, v) : \r
- (t==5) ? GetJMixQuestionDetails(hp, v) : \r
- (t==6) ? GetJQuizQuestionDetails(hp, v) :\r
- (t==7) ? GetRhubarbDetails(hp, v) :\r
- (t==8) ? GetSequiturDetails(hp, v) : '';\r
-}\r
-function GetJbcQuestionDetails(hp, v) {\r
- qDetails = '';\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- // get question details \r
- for(var q=0; q<I.length; q++) {\r
- // initialize strings to hold answer details\r
- var aDetails = new Array();\r
- aDetails[0] = new Array(); // right\r
- aDetails[1] = new Array(); // wrong\r
- aDetails[2] = new Array(); // ignored\r
- // get answer details\r
- for(var a=0; a<I[q][1].length; a++) {\r
- var i = (Status[q][1][a]=='R') ? 0 : (Status[q][1][a]=='0') ? 2 : 1; \r
- aDetails[i][aDetails[i].length] = (JBC[6] ? a : I[q][1][a][0]);\r
- }\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JBC', q);\r
- // add separator, if required\r
- if (JBC[0]) qDetails += makeSeparator(Q);\r
- if (JBC[1]) { // number of attempts to answer question\r
- qDetails += hpHiddenField(Q+'attempts', Status[q][2] + (Status[q][0]==1 ? 1 : 0));\r
- }\r
- if (JBC[2]) { // question text\r
- qDetails += hpHiddenField(Q+'text', I[q][0]);\r
- }\r
- if (JBC[3] && (DB[0] || aDetails[0].length>0)) { // right\r
- qDetails += hpHiddenField(Q+'right', aDetails[0]);\r
- }\r
- if (JBC[4] && (DB[0] || aDetails[1].length>0)) { // wrong\r
- qDetails += hpHiddenField(Q+'wrong', aDetails[1]);\r
- }\r
- if (JBC[5] && (DB[0] || aDetails[2].length>0)) { // ignored\r
- qDetails += hpHiddenField(Q+'ignored', aDetails[2]);\r
- }\r
- // calculate score for this question, if required (for HP version < 5.5)\r
- if (isNaN(Status[q][3])) {\r
- var a1 = Status[q][1].length; // answers\r
- var a2 = Status[q][2]; // attempts\r
- Status[q][3] = (a1<1 || a1<(a2-1)) ? 0 : ((a1 - (a2-1)) / a1);\r
- }\r
- // add 'score' for this question\r
- qDetails += hpHiddenField(Q+'score', Math.floor(Status[q][3]*100)+'%');\r
- } // end for\r
- }\r
- return qDetails;\r
-}\r
-function GetJClozeQuestionDetails(hp, v) {\r
- var qDetails = '';\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- var r = hpRottmeier();\r
- if (parseInt(r)==2) { // Rottmeier Find-It 3a+3b\r
- qDetails += hpHiddenField('JCloze_penalties', window.TotWrongChoices);\r
- }\r
- // get details for each question\r
- var q_max = (r==0) ? State.length : GapList.length; // could use I.length for both\r
- for (var q=0; q<q_max; q++) {\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JCloze', q);\r
- // add separator, if required\r
- if (JCloze[0]) qDetails += makeSeparator(Q);\r
- // score (as %)\r
- var x = (hp==5) ? State[q][3] : (r==0) ? State[q].ItemScore : GapList[q][1].Score;\r
- qDetails += hpHiddenField(Q+'score', Math.floor(x*100)+'%');\r
- var correct = (HP[_correct][q] ? HP[_correct][q] : '');\r
- if (JCloze[1]) { // student's correct answer\r
- qDetails += hpHiddenField(Q+'correct', correct);\r
- }\r
- if (JCloze[2]) { // ignored answers\r
- var x = new Array();\r
- if (r!=2.1) { // exclude Find-It 3a\r
- for (var i=0, ii=0; i<I[q][1].length; i++) {\r
- var s = I[q][1][i][0];\r
- if (typeof(s)=='string' && s!='' && (s.toUpperCase() != correct.toUpperCase())) {\r
- x[ii++] = s;\r
- }\r
- }\r
- }\r
- qDetails += hpHiddenField(Q+'ignored', x);\r
- }\r
- if (JCloze[3]) {\r
- var x = (HP[_wrong][q] ? HP[_wrong][q] : '');\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (JCloze[4]) { // number of penalties (Hints + Checks)\r
- var x = (hp==5) ? State[q][1] : (r==0) ? State[q].HintsAndChecks : (r==1) ? GapList[q][1].NumOfTrials : (r==2.2) ? GapList[q][1].HintsAndChecks : 0;\r
- qDetails += hpHiddenField(Q+'penalties', x);\r
- }\r
- if (JCloze[5]) { // clue shown?\r
- var x = (hp==5) ? State[q][0] : (r==0) ? State[q].ClueGiven: (r==1) ? GapList[q][1].ClueAskedFor : false;\r
- qDetails += hpHiddenField(Q+'clue_shown', (x ? 'YES' : 'NO'));\r
- }\r
- if (JCloze[6]) { // clue text\r
- qDetails += hpHiddenField(Q+'clue_text', I[q][2]);\r
- }\r
- if (JCloze[7]) { // number of hints\r
- var x = (HP[_hints][q] ? HP[_hints][q] : 0);\r
- qDetails += hpHiddenField(Q+'hints', x);\r
- }\r
- if (JCloze[8]) { // number of clues\r
- var x = HP[_clues][q] ? HP[_clues][q] : 0;\r
- qDetails += hpHiddenField(Q+'clues', x);\r
- }\r
- if (JCloze[9]) { // number of checks (including the final one for the correct answer)\r
- var x = (HP[_checks][q] ? HP[_checks][q] : 0);\r
- qDetails += hpHiddenField(Q+'checks', x);\r
- }\r
- } // end for\r
- }\r
- return qDetails;\r
-}\r
-function GetJCrossQuestionDetails(hp, v) {\r
- var qDetails = '';\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- // inialize letter count\r
- var letters = 0;\r
- // get details for each question\r
- for (var row=0; row<L.length; row++) {\r
- for (var col=0; col<L[row].length; col++) {\r
- // increment letter count, if required\r
- if (L[row][col]) letters++; \r
- // show answers and clues, if required\r
- var q = (hp==5) ? C[row][col] : CL[row][col];\r
- if (q) {\r
- for (var i=0; i<2; i++) { // 0==across, 1==down\r
- var AD = (i==0) ? 'A' : 'D';\r
- var acrossdown = (i==0) ? 'across' : 'down';\r
- \r
- var clue = (hp==5) ? eval(AD+'['+q+']') : GetJCrossClue('Clue_'+AD+'_'+q);\r
- if (clue) {\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JCross', q) + acrossdown + '_'; // e.g. JCross_01_across_\r
- \r
- if (JCross[0]) {\r
- qDetails += makeSeparator(Q);\r
- }\r
- if (JCross[5]) {\r
- var x = (HP[_correct][AD] && HP[_correct][AD][q]) ? HP[_correct][AD][q] : '';\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (JCross[4]) qDetails += hpHiddenField(Q+'clue', clue);\r
- if (JCross[5]) {\r
- var x = (HP[_wrong][AD] && HP[_wrong][AD][q]) ? HP[_wrong][AD][q] : '';\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (JCross[6]) {\r
- var x = HP[_clues][q] ? HP[_clues][q] : 0;\r
- qDetails += hpHiddenField(Q+'clues', x);\r
- }\r
- if (JCross[7]) {\r
- var x = (HP[_hints][AD] && HP[_hints][AD][q]) ? HP[_hints][AD][q] : 0;\r
- qDetails += hpHiddenField(Q+'hints', x);\r
- }\r
- if (JCross[8]) {\r
- var x = (HP[_checks][AD] && HP[_checks][AD][q]) ? HP[_checks][AD][q] : '';\r
- qDetails += hpHiddenField(Q+'checks', x);\r
- }\r
- } // end for i\r
- } // end if clue\r
- } // end if q\r
- } // end for col\r
- } // end for row\r
- if (JCross[2]) { // show number of letters\r
- qDetails = hpHiddenField('JCross_letters', letters) + qDetails;\r
- }\r
- if (JCross[1]) { // show penalties\r
- var x = (window.Penalties) ? Penalties : 0;\r
- qDetails = hpHiddenField('JCross_penalties', x) + qDetails;\r
- }\r
- }\r
- return qDetails;\r
-}\r
-function GetJCrossClue(id) {\r
- var obj = (document.getElementById) ? document.getElementById(id) : null;\r
- return (obj) ? GetTextFromNodeN(obj, 'Clue') : '';\r
-}\r
-function GetJCrossWord(a, r, c, goDown) {\r
- // a is a 2-dimensional array of letters, r is a row number, c is a column number\r
- var s = '';\r
- while (r<a.length && c<a[r].length && a[r][c]) {\r
- s += a[r][c];\r
- if (goDown) {\r
- r++;\r
- } else {\r
- c++;\r
- }\r
- }\r
- return s;\r
-}\r
-function GetJMatchText(q, className) {\r
- var obj = (document.getElementById) ? document.getElementById('Questions') : null;\r
- return (obj) ? GetTextFromNodeN(obj, className, q) : '';\r
-}\r
-function GetJMatchRHS(v, q, getCorrect) {\r
- var rhs = '';\r
- if (v==5.1 || v==6.1) { // Drag-and-drop\r
- var max_i = (window.F && window.D) ? D.length : 0;\r
- for (var i=0; i<max_i; i++) {\r
- if (F[q][1]==D[i][getCorrect ? 1 : 2]) break;\r
- }\r
- if (i<max_i) rhs = D[i][0];\r
- } else if (v==5 || v==6) { // drop-down list of options\r
- var obj=document.getElementById(Status[q][2]);\r
- if (obj) { // not correct yet\r
- if (getCorrect) {\r
- var k = GetKeyFromSelect(obj);\r
- var i_max = obj.options.length;\r
- for (var i=0; i<i_max; i++) {\r
- if (obj.options[i].value==k) break;\r
- }\r
- if (i>=i_max) i = 0; // shouldn't happen\r
- } else {\r
- // get current guess, if any\r
- var i = obj.selectedIndex;\r
- }\r
- if (i) rhs = obj.options[i].innerHTML;\r
- } else { // correct\r
- rhs = GetJMatchText(q, 'RightItem');\r
- }\r
- }\r
- return rhs;\r
-}\r
-function GetJMixQuestionDetails(hp, v) {\r
- qDetails = '';\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- var q = 0; // question number\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JMix', q);\r
- // add separator, if required\r
- if (JMix[0]) qDetails += makeSeparator(Q);\r
- // add 'score' for this question\r
- var score = HP[_correct]==null ? 0 : ((Segments.length-Penalties)/Segments.length);\r
- qDetails += hpHiddenField(Q+'score', Math.floor(score*100)+'%');\r
- if (JMix[1]) { // number of wrong guesses\r
- qDetails += hpHiddenField(Q+'wrongGuesses', Penalties);\r
- }\r
- if (JMix[2]) { // right answer\r
- var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (JMix[3]) { // wrong answer(s)\r
- var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (JMix[5]) { // checks\r
- var x = (HP[_checks][q]) ? HP[_checks][q] : 0;\r
- qDetails += hpHiddenField(Q+'checks', x);\r
- }\r
- if (JMix[6]) { // hints\r
- var x = (HP[_hints][q]) ? HP[_hints][q] : 0;\r
- qDetails += hpHiddenField(Q+'hints', x);\r
- }\r
- }\r
- return qDetails;\r
-}\r
-function GetJMixSequence(indexes) {\r
- var s = new Array();\r
- for (var i=0; i<indexes.length; i++) {\r
- s[i] = JMix[4] ? indexes[i] : GetJMixSegmentText(indexes[i]);\r
- }\r
- return s;\r
-}\r
-function GetJMixSegmentText(index){\r
- var i_max = Segments.length;\r
- for (var i=0; i<i_max; i++) {\r
- if (Segments[i][1] == index) break;\r
- }\r
- return (i<i_max) ? Segments[i][0] : '';\r
-}\r
-function GetJQuizQuestionDetails(hp, v) {\r
- var qDetails = '';\r
- // HP5.5 uses "Status" for v5 and v6 JMatch quizzes (HP6 uses "State")\r
- // var hp = (window.Status) ? 5 : (window.State) ? 6 : 0;\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- // get details for each question\r
- var max_q = (hp==5) ? Status.length : State.length;\r
- for (var q=0; q<max_q; q++) {\r
- // skip this question if it was not used (HP6 v6 only)\r
- if (hp==6 && !State[q]) continue;\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JQuiz', q);\r
- // add separator\r
- if (JQuiz[0]) qDetails += makeSeparator(Q);\r
- if (hp==6 && JQuiz[11]) { // question type\r
- var x = parseInt(I[q][2]);\r
- x = (x==0) ? 'multiple-choice' : (x==1) ? 'short-answer' : (x==2) ? 'hybrid' : (x==3) ? 'multi-select' : 'n/a';\r
- qDetails += hpHiddenField(Q+'type', x);\r
- }\r
- // score (as %)\r
- var x = (hp==5) ? Status[q][4]*10 : I[q][0]*State[q][0];\r
- if (x<0) x = 0;\r
- qDetails += hpHiddenField(Q+'score', Math.floor(x)+'%');\r
- if (hp==6 && JQuiz[10]) { // weighting\r
- qDetails += hpHiddenField(Q+'weighting', I[q][0]);\r
- }\r
- if (JQuiz[1]) { // question text\r
- var x = (hp==5) ? I[q][0] : (document.getElementById) ? GetTextFromNodeN(document.getElementById('Q_'+q), 'QuestionText') : '';\r
- qDetails += hpHiddenField(Q+'question', x);\r
- }\r
- if (JQuiz[2]) { // student's correct answers\r
- var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (JQuiz[3]) { // ignored and wrong answers\r
- var x = (hp==5) ? new Array() : GetJQuizAnswerDetails(q, 1);\r
- if (hp==5) {\r
- for (var i=0; i<I[q][1].length; i++) {\r
- var correct = HP[_correct][q] ? HP[_correct][q] : '';\r
- if (I[q][1][i][0] && I[q][1][i][0].toUpperCase()!=correct.toUpperCase()) {\r
- x[x.length] = I[q][1][i][0];\r
- }\r
- }\r
- }\r
- if (DB[0] || x) qDetails += hpHiddenField(Q+'other', x);\r
- }\r
- if (hp==6 && JQuiz[7]) { // all selected answers\r
- var x = GetJQuizAnswerDetails(q, 0);\r
- qDetails += hpHiddenField(Q+'selected', x);\r
- }\r
- if (JQuiz[8]) { // wrong answers\r
- var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (hp==6 && JQuiz[9]) { // ignored answers\r
- var x = GetJQuizAnswerDetails(q, 4);\r
- qDetails += hpHiddenField(Q+'ignored', x);\r
- }\r
- if (JQuiz[4]) { // number of hints\r
- var x = (HP[_hints][q]) ? HP[_hints][q] : 0;\r
- qDetails += hpHiddenField(Q+'hints', x);\r
- }\r
- if (JQuiz[5] || JQuiz[12]) { // number of checks\r
- if (JQuiz[12]) { // strictly checks only\r
- var x = (HP[_checks][q]) ? HP[_checks][q] : 0;\r
- } else { // checks (+ hints in HP6)\r
- var x = (hp==5) ? Status[q][1] : (State[q][2]-1);\r
- }\r
- qDetails += hpHiddenField(Q+'checks', x);\r
- }\r
- if (JQuiz[13]) { // ShowAnswer button\r
- var x = (HP[_clues][q]) ? HP[_clues][q] : 0;\r
- qDetails += hpHiddenField(Q+'clues', x);\r
- }\r
- } // end for\r
- } // end if\r
- return qDetails;\r
-}\r
-function GetTextFromNodeN(obj, className, n) {\r
- // returns the text under the nth node of obj with the target class name\r
- var txt = '';\r
- if (obj && className) {\r
- if (typeof(n)=='undefined') {\r
- n = 0;\r
- }\r
- var nodes = GetNodesByClassName(obj, className);\r
- if (n<nodes.length) {\r
- txt += GetTextFromNode(nodes[n]);\r
- }\r
- }\r
- return txt;\r
-}\r
-function GetNodesByClassName(obj, className) {\r
- // returns an array of nodes with the target classname\r
- var nodes = new Array();\r
- if (obj) {\r
- if (className && obj.className==className) {\r
- nodes.push(obj);\r
- } else if (obj.childNodes) {\r
- for (var i=0; i<obj.childNodes.length; i++) {\r
- nodes = nodes.concat(GetNodesByClassName(obj.childNodes[i], className));\r
- }\r
- }\r
- }\r
- return nodes;\r
-}\r
-function GetTextFromNode(obj) {\r
- // return text in (and under) a single DOM node\r
- var txt = '';\r
- if (obj) {\r
- if (obj.nodeType==3) {\r
- txt = obj.nodeValue + ' ';\r
- }\r
- if (obj.childNodes) {\r
- for (var i=0; i<obj.childNodes.length; i++) {\r
- txt += GetTextFromNode(obj.childNodes[i]);\r
- }\r
- }\r
- }\r
- return txt;\r
-}\r
-function GetJQuizAnswerDetails(q, flag) {\r
- // flag : the type of information required about the student's answers\r
- // 0 : all student's answers\r
- // 1 : student's wrong and ignored answers\r
- // 2 : student's correct answers\r
- // 3 : student's wrong answers\r
- // 4 : ignored answers\r
- var x = State[q][5]; //Sequence of answers chosen by number\r
- if (I[q][2]=='3') { // multi-select\r
- if (flag==4) {\r
- var x = new Array();\r
- } else {\r
- // get required part of 'x' and convert to array\r
- var i = x.lastIndexOf('|');\r
- var x = x.substring((flag==2 ? (i+1) : 1), ((flag==0 || flag==2) ? x.length : i)).split('|');\r
- }\r
- for (var i=0; i<x.length; i++) {\r
- var a = new Array();\r
- for (var ii=0; ii<x[i].length; ii++) {\r
- if (x[i].charAt(ii)=='Y') {\r
- var s = JQuiz[6] ? String.fromCharCode(97+ii) : I[q][3][ii][0];\r
- if (s && s.replace && window.RegExp) {\r
- s = s.replace(new RegExp('\\+', 'g'), '+');\r
- }\r
- a.push(s);\r
- }\r
- }\r
- x[i] = a.join('+');\r
- }\r
- } else if (x) { // multiple-choice, short-answer and hybrid \r
- // remove trailing comma and convert to array\r
- x = x.substring(0, x.length-1).split(',');\r
- if (flag) {\r
- var a = new Array();\r
- if (flag==1 || flag==2 || flag==3) {\r
- for (var i=0; i<x.length; i++) {\r
- var ii = I[q][3][(x[i].charCodeAt(0)-65)][2];\r
- if(((flag==1 || flag==2) && ii==1) || (flag==3 && ii==0)) a.push(x[i]);\r
- }\r
- }\r
- if (flag==1) {\r
- x = a;\r
- a = new Array();\r
- }\r
- if (flag==1 || flag==4) {\r
- for (var i=0; i<I[q][3].length; i++) {\r
- var s = String.fromCharCode(65+i);\r
- for (var ii=0; ii<x.length; ii++) {\r
- if (x[ii]==s) break;\r
- }\r
- if (ii==x.length) a.push(s);\r
- }\r
- }\r
- x = a;\r
- }\r
- // convert answer indexes to values, if required\r
- if (JQuiz[6]==false) {\r
- for (var i=0; i<x.length; i++) {\r
- var ii = x[i].charCodeAt(0) - 65;\r
- x[i] = I[q][3][ii][0];\r
- }\r
- }\r
- } else {\r
- x = new Array();\r
- }\r
- return x;\r
-}\r
-function GetRhubarbDetails(v) {\r
- qDetails = '';\r
- if (v==6) {\r
- var q = 0; // always zero\r
- var Q = getQ('Rhubarb', q);\r
- if (document.title) { // use quiz title as question name\r
- qDetails += hpHiddenField(Q+'name', document.title);\r
- }\r
- if (Rhubarb[0]) { // correct words\r
- var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
- if (Rhubarb[1]) { // count of correct words\r
- for (var i=0,ii=0; i<x.length; i++) {\r
- if (x[i]) ii++;\r
- }\r
- x = ii;\r
- }\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (Rhubarb[2]) { // wrong words\r
- var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
- if (Rhubarb[3]) { // count of wrong words\r
- x = x.length;\r
- }\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (Rhubarb[4]) { // ignored\r
- var x = '';\r
- qDetails += hpHiddenField(Q+'ignored', x);\r
- }\r
- if (Rhubarb[5]) { // hints\r
- var x = (HP[_hints][q]) ? HP[_hints][q] : '';\r
- qDetails += hpHiddenField(Q+'hints', x);\r
- }\r
- }\r
- return qDetails;\r
-}\r
-function GetSequiturDetails(v) {\r
- qDetails = '';\r
- if (v==6) {\r
- var q = 0; // always zero\r
- var Q = getQ('Sequitur', q);\r
- if (document.title) { // use quiz title as question name\r
- qDetails += hpHiddenField(Q+'name', document.title);\r
- }\r
- if (Sequitur[0]) { // number of correct buttons chosen\r
- var x = (HP[_correct][q]) ? HP[_correct][q] : '';\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (Sequitur[1]) { // number of wrong buttons chosen\r
- var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- }\r
- return qDetails;\r
-}\r
-// *********************\r
-// click event handlers\r
-// *********************\r
-function hpClick(x, args) {\r
- // x is the button type\r
- // args is either empty, a single argument, or an array of arguments\r
- var btn = (x==1) ? 'Hint' : (x==2) ? 'Clue' : (x==3) ? 'Check' : (x==4) ? 'Enter' : '';\r
- if (btn) {\r
- // convert args to array, if necessary\r
- var t = typeof(args);\r
- if (t=='object') {\r
- // do nothing (args is already an array)\r
- } else if (t=='undefined') {\r
- args = new Array();\r
- } else {\r
- args = new Array(''+args);\r
- }\r
- // call handler for this kind of button\r
- var x = eval('hpClick'+btn+'('+hpVersion()+','+hpQuizType()+','+hpQuizVersion()+',args);');\r
- }\r
-}\r
-function hpClickHint(hp, t, v, args) {\r
- if (t==2 || t==5 || t==6 || t==7) { // JCloze, JMix, JQuiz, Rhubarb\r
- var q = args[0]; // clue/question number\r
- if (!HP[_hints][q]) HP[_hints][q] = 0;\r
- HP[_hints][q]++;\r
- }\r
- if (t==3) { // JCross\r
- if (v==6 || v==5) {\r
- var q = args[0]; // clue/question number\r
- var AD = args[1]; // direction ('A' or 'D')\r
- if (!HP[_hints][AD]) HP[_hints][AD] = new Array();\r
- if (!HP[_hints][AD][q]) HP[_hints][AD][q] = 0;\r
- HP[_hints][AD][q]++;\r
- }\r
- }\r
- return true;\r
-}\r
-function hpClickClue(hp, t, v, args) {\r
- if (t==2 || t==3 || t==6) { // JCloze or JCross, or JQuiz (ShowAnswer button)\r
- var q = args[0]; // clue/question number\r
- if (!HP[_clues][q]) HP[_clues][q] = 0;\r
- HP[_clues][q]++;\r
- }\r
- return true;\r
-}\r
-function hpClickCheck(hp, t, v, args) {\r
- if (t==2) { // JCloze\r
- if (v==5 || v==6) {\r
- var r = hpRottmeier();\r
- var already_correct = 'true';\r
- if (r==0) {\r
- already_correct = (hp==5) ? 'State[i][4]==1' : 'State[i].AnsweredCorrectly==true';\r
- } else if (r==1) { // DropDown\r
- already_correct = 'GapList[i][1].GapLocked==true';\r
- } else if (r==2.1) { // Find-It 3a\r
- already_correct = 'GapList[i][1].ErrorFound==true';\r
- } else if (r==2.2) { // Find-It 3b\r
- already_correct = 'GapList[i][1].GapSolved==true';\r
- }\r
- var i_max = I.length;\r
- for (var i=0; i<i_max; i++) {\r
- if (eval(already_correct)) continue;\r
- var g = '';\r
- if (r==0 || r==2.2) {\r
- g = GetGapValue(i);\r
- } else if (r==1) { // DropDown\r
- if (hp==5) {\r
- g = eval('document.Cloze.Gap'+i+'.value');\r
- } else if (hp==6) {\r
- g = Get_SelectedDropValue(i);\r
- }\r
- } else if (r==2.1 && i==args[0]) { // Find-It 3a\r
- g = I[i][1][0][0];\r
- }\r
- if (g) {\r
- if (!HP[_checks][i]) HP[_checks][i] = 0;\r
- HP[_checks][i]++;\r
- if (!HP[_guesses][i]) HP[_guesses][i] = new Array();\r
- var ii = HP[_guesses][i].length;\r
- // is this a new guess at this gap?\r
- if (ii==0 || g!=HP[_guesses][i][ii-1]) { \r
- HP[_guesses][i][ii] = g;\r
- var G = g.toUpperCase();\r
- \r
- var ii_max = I[i][1].length;\r
- for (var ii=0; ii<ii_max; ii++) {\r
- if (window.CaseSensitive) {\r
- if (g==I[i][1][ii][0]) break;\r
- } else {\r
- if (G==I[i][1][ii][0].toUpperCase()) break;\r
- }\r
- }\r
- \r
- if (ii==ii_max) { // guess is wrong\r
- if (!HP[_wrong][i]) HP[_wrong][i] = new Array();\r
- var ii_max = HP[_wrong][i].length;\r
- for (var ii=0; ii<ii_max; ii++) {\r
- if (HP[_wrong][i][ii]==g) break;\r
- }\r
- if (ii==ii_max) {\r
- HP[_wrong][i][ii] = g;\r
- }\r
- } else { // guess is correct\r
- HP[_correct][i] = g;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if (t==3) { // JCross\r
- if (v==5 || v==6) {\r
- var q = args[0]; // clue/question number\r
- for (var row=0; row<L.length; row++) {\r
- for (var col=0; col<L[row].length; col++) {\r
- var q = (v==5) ? C[row][col] : CL[row][col];\r
- if (q) {\r
- hpClickCheckJCrossV5V6(hp, v, 'A', q, row, col);\r
- hpClickCheckJCrossV5V6(hp, v, 'D', q, row, col);\r
- }\r
- }\r
- }\r
- }\r
- }\r
- if (t==4) { // JMatch\r
- var a = new Array();\r
- var extra = ''; // extra js code to eval(uate)\r
- var guess = ''; // js code to eval(uate) guess\r
- var correct = ''; // js code to eval(uate) correct answer\r
- if (window.D && window.F) {\r
- // drag-and-drop, i.e. v5+ and v6+ (HP5 and HP6)\r
- a = F;\r
- guess = 'GetJMatchRHS(v,i)';\r
- correct = 'GetJMatchRHS(v,i,true)';\r
- } else if (window.GetKeyFromSelect) {\r
- // HP6 v6\r
- a = Status;\r
- guess = 'GetJMatchRHS(v,i)';\r
- correct = 'GetJMatchRHS(v,i,true)';\r
- } else if (window.GetAnswer) {\r
- // HP5 v6,v5\r
- a = I;\r
- guess = "(I[i][2]==0||I[i][0]=='')?'':GetAnswer(i)";\r
- correct = 'I[i][3])';\r
- } else if (window.Draggables) {\r
- // HP5 v4\r
- a = Draggables;\r
- s = "Draggables[i].correct=='1'";\r
- } else if (window.CorrectAnswers) {\r
- // HP5 v3\r
- a = CorrectAnswers;\r
- guess = 'document.QuizForm.elements[i*2].selectedIndex';\r
- correct = 'CorrectAnswers[i]';\r
- }\r
- for (var i=0; i<a.length; i++) {\r
- // check this match has not already been finished\r
- if (!HP[_correct][i]) {\r
- // do extra setup, if necessary\r
- if (extra) eval(extra);\r
- // get the guess, if any\r
- var g = ''+eval(guess);\r
- if (g) {\r
- // is the guess correct?\r
- if (g==eval(correct)) {\r
- HP[_correct][i] = g;\r
- } else { // wrong answer\r
- // initialize wrong guess array if necessary\r
- if (!HP[_wrong][i]) HP[_wrong][i] = new Array();\r
- // check to see if the guess is already in the guess array\r
- var i_max = HP[_wrong][i].length;\r
- for (var ii=0; ii<i_max; ii++) {\r
- if (HP[_wrong][i][ii]==g) break;\r
- }\r
- // add the guess if it was not found\r
- if (ii==i_max) {\r
- HP[_wrong][i][ii]=g;\r
- } else {\r
- g = null; // this is not a new answer\r
- }\r
- }\r
- // increment checks for this question, if necessary\r
- if (g) {\r
- if (!HP[_checks][i]) HP[_checks][i] = 0;\r
- HP[_checks][i]++;\r
- }\r
- }\r
- }\r
- }\r
- } // end if JMatch\r
- if (t==5) { // JMix\r
- // get question number (always 0)\r
- var q = args[0];\r
- // check question has not already been answered correctly\r
- if (!HP[_correct][q]) {\r
- // match current guess against possible correct answers\r
- var a_max = Answers.length;\r
- for (var a=0; a<a_max; a++) {\r
- var i_max = Answers[a].length;\r
- for (var i=0; i<i_max; i++) {\r
- if (Answers[a][i] != GuessSequence[i]) break;\r
- }\r
- if (i==i_max) break; // correct answer was found\r
- }\r
- // at this point, (a==a_max) means guess is wrong\r
- // get array of segment texts in this g(uess)\r
- var g = GetJMixSequence(GuessSequence);\r
- // convert g(uess) array and to a s(tring)\r
- var s = '';\r
- var i_max = g.length;\r
- for (var i=0; i<i_max; i++) {\r
- g[i] = trim(g[i]);\r
- if (g[i]!='') {\r
- s += (s=='' ? '' : '+') + g[i];\r
- }\r
- }\r
- if (s) {\r
- if (a==a_max) { // wrong\r
- if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
- var i = HP[_wrong][q].length;\r
- HP[_wrong][q][i] = s;\r
- } else { // correct\r
- HP[_correct][q] = s;\r
- }\r
- // increment checks for this question\r
- if (!HP[_checks][q]) HP[_checks][q] = 0;\r
- HP[_checks][q]++;\r
- }\r
- }\r
- }\r
- if (t==6) { // JQuiz\r
- if (hp==5 || hp==6) {\r
- var q = args[0]; // clue/question number\r
- if (hp==5) {\r
- if (v==5) {\r
- var g = TrimString(eval('BottomFrame.document.QForm' + q + '.Guess').value);\r
- } else if (v==6) {\r
- var g = TrimString(eval('document.QForm.Guess').value);\r
- }\r
- } else { // HP 6\r
- var g = args[1];\r
- }\r
- // increment check count\r
- if (!HP[_checks][q]) HP[_checks][q] = 0;\r
- HP[_checks][q]++;\r
- if (g) {\r
- var G = g.toUpperCase(); // used for shortanswer only\r
- var correct_answer = ''; // used for multiselect only\r
- // set index of answer array in I (the question array)\r
- var ans = (hp==5) ? 1 : 3;\r
- var i_max = I[q][ans].length;\r
- for (var i=0; i<i_max; i++) {\r
- // is this a (possible) correct answer?\r
- if (hp==5 || (hp==6 && I[q][ans][i][2])) {\r
- if (hp==6 && I[q][2]==3) { // multiselect\r
- correct_answer += (correct_answer ? '+' : '') + I[q][ans][i][0];\r
- } else { // multichoice, shortanswer\r
- if (window.CaseSensitive) {\r
- if (g==I[q][ans][i][0]) break;\r
- } else {\r
- if (G==I[q][ans][i][0].toUpperCase()) break;\r
- }\r
- }\r
- }\r
- }\r
- if (i==i_max && g!=correct_answer) { // wrong\r
- if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
- var i_max = HP[_wrong][q].length;\r
- for (var i=0; i<i_max; i++) {\r
- if (HP[_wrong][q][i]==g) break;\r
- }\r
- if (i==i_max) HP[_wrong][q][i] = g;\r
- } else {\r
- HP[_correct][q] = g;\r
- }\r
- }\r
- }\r
- }\r
- if (t==7) { // Rhubarb\r
- if (hp==6) {\r
- var q = 0; // question number (always zero)\r
- var g = args[0]; // InputWord from CheckGuess()\r
- if (g) {\r
- var G = g.toUpperCase();\r
- var i_max = Words.length;\r
- for (var i=0; i<i_max; i++) {\r
- if (G==Words[i].toUpperCase()) break;\r
- }\r
- if (i<i_max) { // correct\r
- if (!HP[_correct][q]) HP[_correct][q] = new Array();\r
- HP[_correct][q][i] = g;\r
- } else { // wrong\r
- if (!HP[_wrong][q]) HP[_wrong][q] = new Array();\r
- var i_max = HP[_wrong][q].length;\r
- for (var i=0; i<i_max; i++) {\r
- if (G==HP[_wrong][q][i].toUpperCase()) break;\r
- }\r
- if (i==i_max) HP[_wrong][q][i] = g;\r
- }\r
- }\r
- }\r
- }\r
- if (t==8) { // Sequitur\r
- if (hp==6) {\r
- var q = 0; // question number (always zero)\r
- if (CurrentCorrect==args[0]) { // correct button chosen\r
- if (!HP[_correct][q]) HP[_correct][q] = 0;\r
- HP[_correct][q]++;\r
- } else {\r
- if (!HP[_wrong][q]) HP[_wrong][q] = 0;\r
- HP[_wrong][q]++;\r
- } \r
- }\r
- }\r
- return true;\r
-}\r
-function hpClickCheckJCrossV5V6(hp, v, AD, q, row, col) {\r
- // v is the version of Hot Potatoes\r
- // AD is the direction ('A' or 'D')\r
- // make sure HP[_checks] and HP[_correct] are initialized\r
- if (!HP[_checks][AD]) HP[_checks][AD] = new Array();\r
- if (!HP[_correct][AD]) HP[_correct][AD] = new Array();\r
- // get clue, if any\r
- var clue = (hp==5) ? eval('window.'+AD) : GetJCrossClue('Clue_'+AD+'_' + q);\r
- // is this a question that has not been answered correctly yet?\r
- if (clue && !HP[_correct][AD][q]) {\r
- var check = false;\r
- var guess = GetJCrossWord(G, row, col, (AD=='D'));\r
- var correct = GetJCrossWord(L, row, col, (AD=='D'));\r
- if (guess==correct) {\r
- HP[_correct][AD][q] = correct;\r
- check = true;\r
- } else if (guess) {\r
- // make sure HP[_wrong] is initialized\r
- if (!HP[_wrong][AD]) HP[_wrong][AD] = new Array();\r
- if (!HP[_wrong][AD][q]) HP[_wrong][AD][q] = new Array();\r
- // check this guess has not been entered before\r
- var i_max = HP[_wrong][AD][q].length;\r
- for (var i=0; i<i_max; i++) {\r
- if (HP[_wrong][AD][q]==guess) break;\r
- }\r
- // add the guess if it has not been entered before\r
- if (i>=i_max) {\r
- HP[_wrong][AD][q][i] = guess;\r
- check = true;\r
- }\r
- }\r
- // update HP[_checks], if necessary\r
- if (check) {\r
- if (!HP[_checks][AD]) HP[_checks][AD] = new Array();\r
- if (!HP[_checks][AD][q]) HP[_checks][AD][q] = 0;\r
- HP[_checks][AD][q]++;\r
- }\r
- }\r
-}\r
-function hpClickEnter(hp, t, v, args) {\r
- if (t==3) { // JCross\r
- var q = args[0]; // clue/question number\r
- if (!HP[_enter][q]) HP[_enter][q] = 0;\r
- HP[_enter][q]++;\r
- }\r
- return true;\r
-}\r
-function GetJMatchQuestionDetails(hp, v) {\r
- var qDetails = '';\r
- // HP5.5 uses "I" for v5 and v6 JMatch quizzes\r
- // var hp5 = (window.I) ? true : false;\r
- // check the quiz version\r
- if (hp==5 || hp==6) {\r
- if (JMatch[1] && v==6.1) { // attempts\r
- qDetails += hpHiddenField('JMatch_attempts', Penalties+1);\r
- }\r
- // get number of questions\r
- var max_q = (hp==5 || v==6) ? Status.length : F.length;\r
- // get details for each question\r
- for (var q=0; q<max_q; q++) {\r
- // format 'Q' (a padded, two-digit version of 'q')\r
- var Q = getQ('JMatch', q);\r
- // add separator, if required\r
- if (JMatch[0] && (JMatch[1] || JMatch[2] || JMatch[3])) {\r
- qDetails += makeSeparator(Q);\r
- }\r
- if (JMatch[1] && (hp==5 || v==6)) { // attempts\r
- qDetails += hpHiddenField(Q+'attempts', Status[q][1]);\r
- }\r
- if (JMatch[2]) { // LHS text (the question)\r
- var x = (v==5) ? I[q][0] : (v==6) ? GetJMatchText(q, 'LeftItem') : F[q][0];\r
- qDetails += hpHiddenField(Q+'lhs', x);\r
- }\r
- if (JMatch[3]) { // correct answer (if any)\r
- var x = HP[_correct][q] ? HP[_correct][q] : '';\r
- qDetails += hpHiddenField(Q+'correct', x);\r
- }\r
- if (JMatch[4]) { // wrong answers (if any)\r
- var x = HP[_wrong][q] ? HP[_wrong][q] : '';\r
- qDetails += hpHiddenField(Q+'wrong', x);\r
- }\r
- if (JMatch[5]) { // checks\r
- var x = HP[_checks][q] ? HP[_checks][q] : 0;\r
- qDetails += hpHiddenField(Q+'checks', x);\r
- }\r
- } // end for\r
- }\r
- return qDetails;\r
-}\r
-// *********************\r
-// library functions\r
-// *********************\r
-function pad(i, l) {\r
- var s = (i+'');\r
- while (s.length<l) s = '0' + s;\r
- return s;\r
-}\r
-function getQ(section, q) {\r
- // Q is a padded, two-digit version of the question number, 'q', prefixed by 'section'\r
- return section + '_q' + (q<9 ? '0' : '') + (q+1) + '_';\r
-}\r
-function makeSeparator(Q) {\r
- return is_LMS() ? '' : hpHiddenField(Q.substring(0, Q.length-1), '---------------------------------');\r
-}\r
-function hpHiddenField(name, value, comma, forceHTML) {\r
- var field = '';\r
- var t = typeof(value);\r
- if (t=='string') {\r
- value = encode_entities(value);\r
- } else if (t=='object') { // array\r
- var values = value;\r
- var i_max = values.length;\r
- value = '';\r
- if (comma==null) comma = ','; \r
- for (var i=0; i<i_max; i++) {\r
- values[i] = trim(values[i]);\r
- if (values[i]!='') {\r
- value += (i==0 ? '' : comma) + encode_entities(values[i]);\r
- }\r
- }\r
- }\r
- if (is_LMS() && !forceHTML) {\r
- if (value && value.indexOf && value.indexOf('<')>=0 && value.indexOf('>')>=0) {\r
- value = '<![CDATA[' + value + ']]>';\r
- }\r
- field = '<field><fieldname>' + name + '</fieldname><fielddata>' + value + '</fielddata></field>';\r
- } else {\r
- field = '<input type=hidden name="' + name + '" value="' + value + '">';\r
- }\r
- return field;\r
-}\r
-function trim(s) {\r
- if (s==null) s = '';\r
- var i = 0;\r
- var ii = s.length;\r
- while (i<ii && s.charAt(i)==' ') {\r
- i++;\r
- }\r
- while (ii>i && s.charAt(ii-1)==' ') {\r
- ii--;\r
- }\r
- return s.substring(i, ii);\r
-}\r
-function encode_entities(s_in) {\r
- var i_max = (s_in) ? s_in.length : 0;\r
- var s_out = '';\r
- for (var i=0; i<i_max; i++) {\r
- var c = s_in.charCodeAt(i);\r
- // 34 : double quote .......["] &\r
- // 38 : single quote .......['] '\r
- // 43 : plus sign ..........[+]\r
- // 44 : comma ..............[,]\r
- // 60 : left angle bracket .[<] <\r
- // 62 : right angle bracket [>] >\r
- // >=128 multibyte character\r
- s_out += (c==43 || c==44 || c>=128) ? ('&#x' + pad(c.toString(16), 4) + ';') : s_in.charAt(i);\r
- }\r
- return s_out;\r
-}\r
-// *********************\r
-// initialization\r
-// functions\r
-// *********************\r
-function getTime(obj) {\r
- obj = obj ? obj : new Date();\r
- // get year, month and day\r
- // for an LMS : yyyy-mm-dd\r
- // for email : DayName MonthName dd yyyy\r
- var s = is_LMS() ? \r
- obj.getFullYear() + '-' + pad(obj.getMonth()+1, 2) + '-' + pad(obj.getDate(), 2) : \r
- MSG[16][obj.getDay()] + ' ' + MSG[17][obj.getMonth()] + ' ' + pad(obj.getDate(), 2) + ' ' + obj.getFullYear()\r
- ;\r
- // get hours, minutes and seconds (hh:mm:ss)\r
- s += ' ' + pad(obj.getHours(), 2) + ':' + pad(obj.getMinutes(), 2) + ':' + pad(obj.getSeconds(), 2);\r
- // get time difference\r
- // for an LMS : +xxxx\r
- // for email : GMT+xxxx\r
- var x = obj.getTimezoneOffset(); // e.g. -540\r
- if (!isNaN(x)) {\r
- s += ' ' + (is_LMS() ? '' : 'GMT') + (x<0 ? '+' : '-');\r
- x = Math.abs(x);\r
- s += pad(parseInt(x/60), 2) + pad(x - (parseInt(x/60)*60), 2);\r
- }\r
- return s;\r
-}\r
-function getFunc(fn) {\r
- if (typeof(fn)=='string') {\r
- fn = eval('window.' + fn);\r
- }\r
- return (typeof(fn)=='function') ? fn : null;\r
-}\r
-function getFuncCode(fn, extraCode, anchorCode, beforeAnchor) {\r
- var s = '';\r
- var obj = getFunc(fn);\r
- if (obj) {\r
- s = obj.toString();\r
- var i1 = s.indexOf('{')+1;\r
- var i2 = s.lastIndexOf('}');\r
- if (i1>0 && i1<i2) {\r
- s = s.substring(i1, i2);\r
- }\r
- }\r
- if (extraCode) {\r
- if (anchorCode) {\r
- if (beforeAnchor) {\r
- s = replaceLast(anchorCode, extraCode + anchorCode, s);\r
- } else {\r
- s = replaceLast(anchorCode, anchorCode + extraCode, s);\r
- }\r
- } else {\r
- if (beforeAnchor) {\r
- s = extraCode + s;\r
- } else {\r
- s = s + extraCode;\r
- }\r
- }\r
- }\r
- return s;\r
-}\r
-function getArgsStr(args) {\r
- // make s(tring) version of function args array\r
- var s = '';\r
- var i_max = args.length;\r
- for (var i=0; i<i_max; i++) {\r
- s += '"' + args[i] + '",';\r
- }\r
- return s;\r
-}\r
-function getFuncArgs(fn, flag) {\r
- // flag==0 : return args as string\r
- // flag==1 ; return args as array\r
- var i = 0;\r
- var a = new Array();\r
- var obj = getFunc(fn);\r
- if (obj) {\r
- var s = obj.toString();\r
- var i1 = s.indexOf('(') + 1;\r
- var i2 = s.indexOf(')', i1);\r
- // add args to a(rray)\r
- while (i1>0 && i1<i2) {\r
- var i3 = s.indexOf(',', i1); // next comma\r
- if (i3<0 || i3>i2) i3 = i2;\r
- a[i++] = trim(s.substring(i1, i3));\r
- i1 = i3+1;\r
- }\r
- }\r
- return flag ? a : getArgsStr(a);\r
-}\r
-function getPrompt(fn) {\r
- // the LoginPrompt is the text string in the first prompt(...) statement\r
- // v5 : in the StartUp function\r
- // v6 : in the GetUserName function\r
- // Note: netscape uses double-quote as delimiter, others use single quote\r
- var s = getFuncCode(fn);\r
- var i1 = s.indexOf('prompt') + 8;\r
- var i2 = s.indexOf(s.charAt(i1-1), i1); \r
- var p = (i1>=8 && i2>i1) ? s.substring(i1, i2) : '';\r
- // make sure browser has decoded the unicode prompt properly\r
- // this check is mainly for ns4, but there may be others\r
- if (window.RegExp) {\r
- var r = new RegExp('u([0-9A-F]{4})');\r
- var m = r.exec(p);\r
- while (m) {\r
- p = p.replace(m[0], '&#' + parseInt(m[1], 16) + ';');\r
- m = r.exec(p);\r
- }\r
- }\r
- return p;\r
-}\r
-function getStartUpCode(fn) {\r
- // the main initialization code comes from the StartUp function\r
- // v5 : the code before "UserName", if any, \r
- // and the code after the 2nd subsequent '}'\r
- // v6 : the code before and after 'GetUserName();' \r
- // i.e. all the code except the call to 'GetUserName();'\r
- var s = getFuncCode(fn);\r
- var i1 = s.indexOf('GetUserName();');\r
- if (i1>=0) { // v6 \r
- var i2 = i1 + 14;\r
- } else { // v5\r
- var i1 = s.indexOf('UserName');\r
- var i2 = s.indexOf('}', s.indexOf('}', i1+8)+1)+1;\r
- }\r
- return (0<i1 && i1<i2) ? s.substring(0, i1) + s.substring(i2) : '';\r
-}\r
-function is_LMS() {\r
- if (!window.hpCheckedForm) {\r
- window.hpCheckedForm = true;\r
- window.hpFoundForm = hpFindForm('store') ? true : false;\r
- }\r
- return hpFoundForm;\r
-}\r
-function hpFeedback() {\r
- if (FEEDBACK[0]) {\r
- var url = '';\r
- var html = '';\r
- if (FEEDBACK[1] && FEEDBACK[2]) { // formmail\r
- html += '<html><body>'\r
- + '<form action="' + FEEDBACK[0] + '" method="POST">'\r
- + '<table border="0">'\r
- + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'\r
- + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'\r
- ;\r
- if (typeof(FEEDBACK[1])=='string') {\r
- html += FEEDBACK[1] + hpHiddenField('recipient', FEEDBACK[1], ',', true);\r
- } else if (typeof(FEEDBACK[1])=='object') {\r
- var i_max = FEEDBACK[1].length;\r
- if (i_max==1) { // one teacher\r
- html += FEEDBACK[1][0][0] + hpHiddenField('recipient', FEEDBACK[1][0][0]+' <'+FEEDBACK[1][0][1]+'>', ',', true);\r
- } else if (i_max>1) { // several teachers\r
- html += '<select name="recipient">';\r
- for (var i=0; i<i_max; i++) {\r
- html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';\r
- }\r
- html += '</select>';\r
- }\r
- }\r
- html += '</td></tr>'\r
- + '<tr><th valign="top" align="right">' + FEEDBACK[9] + ':</th>'\r
- + '<td><TEXTAREA name="message" rows="10" cols="40"></TEXTAREA></td></tr>'\r
- + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">'\r
- + hpHiddenField('realname', FEEDBACK[2], ',', true)\r
- + hpHiddenField('email', FEEDBACK[3], ',', true)\r
- + hpHiddenField('subject', document.title, ',', true)\r
- + hpHiddenField('title', document.title, ',', true)\r
- + hpHiddenField('return_link_title', FEEDBACK[10], ',', true)\r
- + hpHiddenField('return_link_url', 'javascript:self.close()', ',', true)\r
- + '</td></tr></table></form></body></html>'\r
- ;\r
- } else if (FEEDBACK[1]) { // url only\r
- if (typeof(FEEDBACK[1])=='object') {\r
- var i_max = FEEDBACK[1].length;\r
- if (i_max>1) { // several teachers\r
- html += '<html><body>'\r
- + '<form action="' + FEEDBACK[0] + '" method="POST" onsubmit="this.action+=this.recipient.options[this.recipient.selectedIndex].value">'\r
- + '<table border="0">'\r
- + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'\r
- + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'\r
- ;\r
- html += '<select name="recipient">';\r
- for (var i=0; i<i_max; i++) {\r
- html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';\r
- }\r
- html += '</select>';\r
- html += '</td></tr>'\r
- + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">'\r
- + '</td></tr></table></form></body></html>'\r
- ;\r
- } else if (i_max==1) { // one teacher\r
- url = FEEDBACK[0] + FEEDBACK[1][0][1];\r
- }\r
- } else if (typeof(FEEDBACK[1])=='string') {\r
- url = FEEDBACK[0] + FEEDBACK[1];\r
- }\r
- } else {\r
- url = FEEDBACK[0];\r
- }\r
- if (url || html) {\r
- var w = openWindow(url, 'feedback', FEEDBACK[4], FEEDBACK[5], 'RESIZABLE,SCROLLBARS', html);\r
- if (!w) {\r
- // unable to open popup window\r
- alert(MSG[18]);\r
- }\r
- }\r
- }\r
-}\r
-// ********************\r
-// intercept clicks\r
-// ********************\r
-function hpInterceptFeedback() {\r
- // modify the function which writes feedback\r
- // v6: ShowMessage(Feedback)\r
- // but Rhubarb prints score in other functions, so use 'CheckFinished'\r
- // v5: WriteFeedback(Feedback)\r
- // v4: WriteFeedback(Stuff)\r
- // v3: WriteFeedback(Feedback) [except JMatch]\r
- // v3: CheckAnswer() [JMatch only]\r
- var f = '';\r
- if (window.CheckWord) { // Rhubarb\r
- f = 'CheckFinished';\r
- window.FEEDBACK = null;\r
- } else if (window.ShowText) { // Sequitur\r
- f = 'CheckAnswer';\r
- window.FEEDBACK = null;\r
- } else { // JBC, JCloze, JCross, JMatch, JMix, JQuiz\r
- f = window.ShowMessage ? 'ShowMessage' : window.WriteFeedback ? 'WriteFeedback' : 'CheckAnswer';\r
- }\r
- if (f) {\r
- var s = getFuncCode(f) + 'Finish();';\r
- var a = getFuncArgs(f, true);\r
- if (a[0] && window.FEEDBACK && FEEDBACK[0]) {\r
- s = a[0] + "+='<br /><br />" + '<a href="javascript:hpFeedback();">' + FEEDBACK[6] + "</A>';" + s;\r
- }\r
- eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
- }\r
-}\r
-function hpInterceptHints() {\r
- // modify the function which shows hints\r
- // JBC: none\r
- // JCloze v3-v6: ShowHint()\r
- // JCross v3: Cheat(), v4: ShowHint(), v5-v6[HP5]: ShowHint(Across,x,y,BoxName), v6[HP6]: ShowHint(Across,ClueNum,x,y,BoxId)\r
- // JMatch: none\r
- // JMix v5-v6: CheckAnswer(CheckType=1)\r
- // JQuiz v3: CheckAnswer(ShowHint=true, QNum), v4: CheckAnswer(ShowHint=true), v5-v6[HP5]: CheckAnswer(ShowHint=true,QNum), v6[HP6]: ShowHint(QNum)\r
- var x = ''; // extra code, if any\r
- if (window.Cheat) {\r
- // JCross v3 ?\r
- } else if (window.ShowHint) {\r
- var f = 'ShowHint';\r
- var a = getFuncArgs(f, true);\r
- if (a.length==0) {\r
- if (window.FindCurrent) {\r
- // JCloze v3-v6\r
- x = 'var q=window.Locked?-1:FindCurrent();if(q>=0&&GetHint(q))hpClick(1,q);';\r
- } else {\r
- // JCross v4\r
- // work out which box would have a hint added\r
- // work out which question that box is part of using GridMap and WinLetters\r
- }\r
- } else if (a[0]=='Across') {\r
- if (a[1]=='ClueNum') {\r
- // JCross v6 [HP6]\r
- x = "var args=new Array(ClueNum,Across?'A':'D');hpClick(1,args);";\r
- } else if (a[1]=='x' && a[2]=='y') {\r
- // JCross v5-v6 [HP5]\r
- x = "var args=new Array(C[x][y],Across?'A':'D');hpClick(1,args);";\r
- }\r
- } else if (a[0]=='QNum') {\r
- // JQuiz v6[HP6]\r
- x = 'hpClick(1,QNum);';\r
- }\r
- } else if (window.Hint) {\r
- // Rhubarb\r
- var f = 'Hint';\r
- var a = getFuncArgs(f, true);\r
- x = 'hpClick(1,0);'; // question number is always zero\r
- \r
- } else if (window.CheckAnswer) {\r
- var f = 'CheckAnswer';\r
- var a = getFuncArgs(f, true);\r
- if (a[0]=='ShowHint') {\r
- if (a[1]=='QNum') {\r
- // JQuiz v3, v5-v6[HP5]\r
- x = 'if(ShowHint)hpClick(1,QNum);'; \r
- } else {\r
- // JQuiz v4\r
- x = 'if(ShowHint)hpClick(1,QNum-1);'; // QNum is a global variable\r
- }\r
- } else if (a[0]=='CheckType') {\r
- // JMix v5-v6\r
- x = 'if(CheckType==1)hpClick(1,0);'; // question number is always 0;\r
- }\r
- }\r
- // add the e(x)tra code, if any, to the start of the hint (f)unction\r
- if (x) {\r
- var s = getFuncCode(f, x, '', true);\r
- eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
- }\r
-}\r
-function hpInterceptClues() {\r
- // modify the function which shows clues (or ShowAnswers in JQuiz)\r
- // JBC: none\r
- // JCloze v3-v6: ShowClue(ItemNum)\r
- // JCross v3-v4: ShowClue(ClueNum), v5-v6: ShowClue(ClueNum,x,y)\r
- // JMatch none\r
- // JMix none\r
- // JQuiz ShowAnswers(QNum)\r
- var x = ''; // extra code, if any\r
- if (window.ShowClue) {\r
- var f = 'ShowClue';\r
- var a = getFuncArgs(f, true);\r
- if (a[0]=='ItemNum') {\r
- // JCloze (v3-v6)\r
- x = 'if(!window.Locked)hpClick(2,ItemNum);'; // v6 [HP6] uses window.Locked\r
- } else if (a[0]=='ClueNum') {\r
- if (a[1]=='x' && a[2]=='y') {\r
- if (window.A && window.D) {\r
- // JCross v5-v6 [HP5]\r
- x = 'if(A[ClueNum]||D[ClueNum])hpClick(2,ClueNum);';\r
- } else if (document.getElementById) {\r
- // JCross v6 [HP6]\r
- x = "if(document.getElementById('clue_' + ClueNum)||document.getElementById('Clue_D_' + ClueNum))hpClick(2,ClueNum);";\r
- }\r
- } else {\r
- if (window.AClues && window.DClues) {\r
- // JCross v3-v4\r
- x = 'if(AClues[ClueNum]||DClues[ClueNum])hpClick(2,ClueNum);';\r
- }\r
- }\r
- }\r
- }\r
- // JQuiz: there is no "ShowClue" function but there is a "ShowAnswer" function\r
- if (window.ShowAnswers) {\r
- var f = 'ShowAnswers';\r
- var a = getFuncArgs(f, true);\r
- if (window.State) {\r
- if (window.ShowMessage) {\r
- // JQuiz v6 [HP6]\r
- x = 'if(State[QNum][0]<1)hpClick(2,QNum);';\r
- } else if (window.WriteFeedback) {\r
- // JQuiz v3-v4\r
- x = 'if(State[QNum-1][0]<1)hpClick(2,QNum-1);';\r
- }\r
- } else if (window.Status) {\r
- // JQuiz v5-v6 [HP5]\r
- x = 'if(Status[QNum][0]<0)hpClick(5,QNum);';\r
- }\r
- }\r
- // add the e(x)tra code, if any, to the start of the clue (f)unction\r
- if (x) {\r
- var s = getFuncCode(f, x, '', true);\r
- eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
- }\r
-}\r
-function hpInterceptChecks() {\r
- // modify the function which handles checks\r
- // JBC: none\r
- // JCloze CheckAnswers()\r
- // NB: Rottmeier Find-It 3a: CheckText(GapState,GapId)\r
- // JCross none\r
- // JMatch HP5 v3, v5, v6: CheckAnswer(), HP5 v4: CheckResults(), HP6: CheckAnswers()\r
- // JMix CheckAnswer(CheckType)\r
- // JQuiz \r
- // HP5: CheckAnswer(ShowHint, QNum)\r
- // HP6: CheckMCAnswer, CheckMultiSelAnswer, CheckShortAnswer\r
- // Rhubarb CheckWord(InputWord)\r
- // Sequitur CheckAnswer(Chosen, Btn)\r
- // HP6 JQuiz has three "Check Answer" functions\r
- var f = new Array('CheckMCAnswer', 'CheckMultiSelAnswer', 'CheckShortAnswer');\r
- for (var i=0; i<f.length; i++) {\r
- if (eval('window.' + f[i])) {\r
- var a = getFuncArgs(f[i], true);\r
- var x = "";\r
- if (f[i]=='CheckMCAnswer') {\r
- x += "var args=new Array(QNum,I[QNum][3][ANum][0]);";\r
- } else if (f[i]=='CheckShortAnswer') {\r
- x += ""\r
- + "var obj=document.getElementById('Q_'+QNum+'_Guess');"\r
- + "var args=new Array(QNum,obj.value);"\r
- ;\r
- } else if (f[i]=='CheckMultiSelAnswer') {\r
- x += ""\r
- + "var g='';"\r
- + "for (var ANum=0; ANum<I[QNum][3].length; ANum++){"\r
- + "var obj=document.getElementById('Q_'+QNum+'_'+ANum+'_Chk');"\r
- + "if (obj.checked)g+=(g?'+':'')+I[QNum][3][ANum][0];"\r
- + "}"\r
- + "var args=new Array(QNum,g);"\r
- ;\r
- }\r
- if (x) {\r
- x = "if(!Finished&&State[QNum].length&&State[QNum][0]<0){" + x + "hpClick(3,args)}";\r
- var s = getFuncCode(f[i], x, '', true);\r
- eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');\r
- }\r
- }\r
- }\r
- var f = ''; // function name\r
- var x = ''; // extra code, if any\r
- if (window.CheckAnswer) {\r
- f = 'CheckAnswer';\r
- var a = getFuncArgs(f, true);\r
- if (a[0]=='ShowHint') {\r
- if (a[1]=='QNum') {\r
- // JQuiz v3, v5-v6[HP5]\r
- x = 'if(!ShowHint&&Status[QNum][0]<1)hpClick(3,QNum);'; \r
- } else {\r
- // JQuiz v4\r
- x = 'if(!ShowHint&&State[QNum-1][0]<1)hpClick(3,QNum-1);'; // QNum is a global variable\r
- }\r
- } else if (a[0]=='CheckType') {\r
- // JMix v5-v6\r
- x = 'if(CheckType==0)hpClick(3,0);'; // question number is always 0;\r
- } else if (a[0]=='Chosen') {\r
- // Sequitur\r
- x = 'if (!(CurrentNumber==TotalSegments||AllDone||Btn.innerHTML==IncorrectIndicator))hpClick(3,Chosen);';\r
- }\r
- } else if (window.CheckWord) { \r
- f = 'CheckWord';\r
- var a = getFuncArgs(f, true);\r
- if (a[0]=='InputWord') {\r
- // Rhubarb\r
- x = 'if(!window.AllDone)hpClick(3,InputWord);';\r
- }\r
- } else if (window.CheckText && !window.CheckAnswers) { // Rottmeier Find-It (3a)\r
- f = 'CheckText';\r
- var a = getFuncArgs(f, true);\r
- if ((a[0]=='bool' && a[1]=='item') || (a[0]=='GapState' && a[1]=='GapId')) {\r
- x = 'if(!window.Finished&&'+a[0]+')hpClick(3,'+a[1]+');';\r
- }\r
- }\r
- if (f) {\r
- var s = getFuncCode(f, x, '', true);\r
- eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');\r
- }\r
- // JMatch has three possible check functions, depending on the version\r
- // (NB: other quiz types also have these functions)\r
- var f = new Array('CheckAnswers', 'CheckAnswer', 'CheckResults');\r
- for (var i=0; i<f.length; i++) {\r
- if (eval('window.' + f[i])) {\r
- var a = getFuncArgs(f[i], true);\r
- if (a.length==0) {\r
- var s = getFuncCode(f[i], "hpClick(3);", '', true);\r
- eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');\r
- break; // out of the loop\r
- }\r
- }\r
- }\r
-}\r
-// ***************\r
-// fix IE5 and NS6\r
-// ***************\r
-// add Array.push if required (allows v6 quizzes to run on ie5win)\r
-if (Array.prototype && Array.prototype.push==null) {\r
- Array.prototype.push = new Function("x", "this[this.length]=x");\r
-}\r
-// add attachEvent function, if required (allows HP5 v6 quizzes to run on ie5mac)\r
-// NOTE: to allow v6 quizzes on ie5mac, the following code \r
-// needs to be inserted BEFORE the Hot Potatoes javascript\r
-if (window.attachEvent==null) {\r
- window.attachEvent = new Function('evt', 'fn', 'eval("window."+evt+"="+fn)');\r
-}\r
-if (document.attachEvent==null) {\r
- document.attachEvent = new Function('evt', 'fn', 'eval("document."+evt+"="+fn)');\r
-}\r
-// fix the ShowMessage function for NS6\r
-// by removing calls to a button's "focus()" method\r
-if (navigator.userAgent.indexOf("Netscape6")>=0 && window.ShowMessage) {\r
- var s = ShowMessage.toString();\r
- var r = new RegExp('document\\.getElementById\\((\'|")FeedbackOKButton(\'|")\\)\\.focus\\(\\);', 'gi');\r
- s = s.substring(s.indexOf('{')+1, s.lastIndexOf('}')).replace(r, '');\r
- window.ShowMessage = new Function('Feedback', s);\r
-}\r
-// ns6.0 (in JMix at least) has an error in the FocusAButton function too\r
-// this could be fixed as follows ...\r
-//if (window.FocusAButton) {\r
-// window.FocusAButton = new Function('return true');\r
-//}\r
-// however, ns6.0 then crashes completely when the mouse moves over a link, so don't bother\r
-// Hot Potatoes quiz sniffing\r
-// === v3 ===\r
-// JBC uses "QuizForm", which contains elements called "Q*_**" (* and ** start at 1)\r
-// JCloze uses "Cloze" form\r
-// JCross uses "Crossword" form\r
-// JMatch uses "QuizForm", which contains elements called "1,2,3..x" and "x+1,x+2...",\r
-// and "CheckForm" form, which contains an element called "ScoreBox"\r
-// it is also the only HP quiz type to use an array called "CorrectAnswers"\r
-// JQuiz uses "QForm*" forms (* starts at 1), which each contain an element called "Guess"\r
-// === v4 ===\r
-// JBC uses "QForm" form in "QuestionDiv", which contains elements called "FB* (* starts at 0)"\r
-// JCloze uses "Cloze" form in "QuestionDiv"\r
-// JCross uses "Crossword" form in "CWDiv"\r
-// JMatch uses "ExCheck" form in "TitleDiv"\r
-// (no JMix in hp4)\r
-// JQuiz uses "QForm" form in "QuestionDiv", which contains an element called "Answer"\r
-// === v5 ===\r
-// JBC uses "QForm" form, which contains elements called "FB_*_**" (* and ** start at 0)\r
-// JCloze uses "Cloze" form\r
-// JCross writes out "AnswerForm" from a variable called "GetAnswerOpener"\r
-// HP5.3: uses "AnswerForm" in "BottomFrame" \r
-// HP5.5: uses "AnswerForm" in "TopFrame", but it is only there when an answer is being input\r
-// JMatch uses "QForm" form, which contains elements called "sel*" (which disappear by the time the quiz is finished)\r
-// JMix uses "ButtonForm"\r
-// JQuiz uses "QForm*" and "Buttons*" (one for each question)\r
-// === v6 ===\r
-// JBC uses "QForm" form (elements have no name or id)\r
-// JCloze uses "Cloze" form (elements have no name or id)\r
-// JCross does not use any forms, \r
-// HP5: has "GridDiv" in "MainDiv"\r
-// HP6: has "Clues" table in "MainDiv"\r
-// JMatch has "MatchDiv" in "MainDiv"\r
-// HP5: uses "QForm" form, which contains elements called "sel*"\r
-// HP6: uses "QForm" form, which contains elements called "s*_**"\r
-// JMix does not use any forms, but has "SegmentDiv" in "MainDiv"\r
-// JQuiz \r
-// HP5: uses "QForm" form, which contains an element called "Guess"\r
-// HP6: has "Questions" ordered list in "MainDiv"\r
-// === v6+ ===\r
-// JMatch has DIVs called "D*" and "F*" (* starts at 0)\r
-// JMix has DIVs called "D*" and "Drop*" (* starts at 0)\r
-// useful sniffing tools (Cut and Paste to browser address box)\r
-//javascript:var s="";var x=new quiz_obj();for(X in x)s+=","+X+"="+x[X];alert(s.substring(1));\r
-//javascript:var s="";var x=document.layers;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))\r
-//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))\r
-function hpDetectQuiz() {\r
- // "sniff" (=detect) the quiz's type and intended browser version\r
- // and cache the values in a global variable called "quiz"\r
- // Hot Potatoes version\r
- // 5 : HP5.3 (mac) or HP5.5 (win)\r
- // 6 : HP6.0 (mac) or HP6.0 (win)\r
- // intended browser version\r
- // 3 : ns3, ie3 (frames)\r
- // 4 : ns4, ie4 (cross browser dhtml)\r
- // 5 : ie5 (frames, send results via CGI)\r
- // 6 : ie6, op7, gecko (w3 standards)\r
- // 6.1 : "drag and drop" versions of JMatch and JMix v6\r
- // quiz type\r
- // 0 : unknown\r
- // 1 : jbc\r
- // 2 : jcloze\r
- // 3 : jcross\r
- // 4 : jmatch\r
- // 5 : jmix\r
- // 6 : jquiz\r
- // 7 : rhubarb (TexToys)\r
- // 8 : Sequitur (TexToys)\r
- // rottmeier quiz type\r
- // 1 : drop-down (JCloze)\r
- // 2 : find-it (JCloze)\r
- // shortcut to window object\r
- var w = window;\r
- // create the global "quiz" object, if necessary\r
- if (!w.quiz) w.quiz = new Object();\r
- // Hot Potatoes version\r
- // HP6 v6: Client()\r
- // HP5 v4-v5: BrowserCheck()\r
- // v3: WinStringToMac() [JCloze, JCross, JQuiz]\r
- // v3: winrightchar [JBC, JMatch]\r
- // v3: DownTime() [JBC, JCloze, JQuiz]\r
- if (!quiz.hp) {\r
- quiz.hp = (w.Client) ? 6 : (w.BrowserCheck) ? 5 : (w.WinStringToMac || w.winrightchar) ? 5 : -1;\r
- }\r
- // check the version and type are not already set\r
- if (!quiz.v || !quiz.t) {\r
- // initialize version and type\r
- var v = 0;\r
- var t = 0;\r
- // set shortcuts to DOM objects\r
- var d = document;\r
- var f = d.forms;\r
- if (f.QuizForm && f.CheckForm && w.CorrectAnswers) {\r
- v = 3;\r
- t = 4; // jmatch\r
- } else if (w.FeedbackFrame && w.CodeFrame) {\r
- v = 3;\r
- f = CodeFrame.document.forms;\r
- t = (f.QuizForm) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.QForm1) ? 6 : 0;\r
- } else if (w.DynLayer) {\r
- v = 4;\r
- if (d.layers) {\r
- // for NS4, adjust "f" to point to a forms object in a layer\r
- var lyr = d.QuestionDiv || d.CWDiv || d.TitleDiv || null;\r
- if (lyr) f = lyr.document.forms;\r
- }\r
- t = (f.QForm && f.QForm.FB0) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.ExCheck) ? 4 : (f.QForm && f.QForm.Answer) ? 6 : 0;\r
- } else if (w.TopFrame && w.BottomFrame) {\r
- v = 5;\r
- f = BottomFrame.document.forms;\r
- t = (f.QForm && f.QForm.elements[0].name.substring(0,3)=='FB_') ? 1 : (f.Cloze) ? 2 : (w.GetAnswerOpener && GetAnswerOpener.indexOf('AnswerForm')>=0) ? 3 : (f.QForm && w.RItems) ? 4 : (f.ButtonForm) ? 5 : (f.QForm0 && f.Buttons0) ? 6 : 0;\r
- } else if (hpObj(d, 'MainDiv')) {\r
- v = 6;\r
- var obj = (f.QForm) ? f.QForm.elements : null;\r
- t = (obj && obj.length>0 && obj[0].id=='') ? 1 : (f.Cloze) ? 2 : (hpObj(d, 'GridDiv') || hpObj(d, 'Clues')) ? 3 : hpObj(d, 'MatchDiv') ? 4 : hpObj(d, 'SegmentDiv') ? 5 : ((f.QForm && f.QForm.Guess) || hpObj(d, 'Questions')) ? 6 : 0;\r
- } else if (hpObj(d, 'D0')) {\r
- v = 6.1; // drag and drop (HP5 and HP6)\r
- t = (hpObj(d, 'F0')) ? 4 : (hpObj(d, 'Drop0')) ? 5 : 0;\r
- } else if (w.Words && f.Rhubarb) {\r
- v = 6;\r
- t = 7; // rhubarb (TexToys)\r
- } else if (w.Segments && hpObj(d, 'Story')) {\r
- v = 6;\r
- t = 8; // sequitur (TexToys)\r
- }\r
- quiz.v = v; // intended browser version\r
- quiz.t = t; // quiz type\r
- }\r
-}\r
-function hpRottmeier() {\r
- hpDetectQuiz();\r
- if (typeof(quiz.r)=='undefined') { // first-time only\r
- quiz.r = 0;\r
- if (quiz.t==2) { // JCloze\r
- if (quiz.hp==5) { // HP5\r
- // ??\r
- } else if (quiz.hp==6) { // HP6\r
- if (window.Create_StateArray) { // Rottmeier\r
- var obj = new Create_StateArray();\r
- if (typeof(obj.GapLocked)=='boolean') {\r
- quiz.r = 1; // drop-down (v2.4)\r
- } else if (typeof(obj.ErrorFound)=='boolean') {\r
- if (typeof(obj.GapSolved)!='boolean') {\r
- quiz.r = 2.1; // find-it (v3.1a)\r
- } else {\r
- quiz.r = 2.2; // find-it (v3.1b)\r
- }\r
- }\r
- obj = null; // prevents memory leakage on some versions of IE\r
- }\r
- }\r
- }\r
- }\r
- return quiz.r;\r
-}\r
-function hpVersion() {\r
- hpDetectQuiz();\r
- return quiz.hp;\r
-}\r
-function hpQuizType() {\r
- hpDetectQuiz();\r
- return quiz.t;\r
-}\r
-function hpQuizVersion() {\r
- hpDetectQuiz();\r
- return quiz.v;\r
-}\r
-function hpScoreEngine(score_i, a, s, aa, ss, count_c, count_i) {\r
- // calculate the score for the quiz so far\r
- // score_i : amount by which to increment "score"\r
- // a : outer array\r
- // s : condition, if any, on outer array (=a)\r
- // if true, the score will be incremented by "score_i"\r
- // aa : inner array, if any\r
- // ss : condition, if any, on inner array (=aa)\r
- // count_c : condition, if any, on which "count" is to be incremented\r
- // count_i : amount by which to increment "count"\r
- // "a" and "aa" may be passed as arrays or strings containing the name of an array\r
- // "s" and "ss" are strings containing an expression to be eval(uated)\r
- // "score_i", "count_i" and "count_c" strings containing an expression to be eval(uated)\r
- var score = 0;\r
- var count = 0;\r
- // set default condition to increment "count", and amount by which to increment the count\r
- if (count_c==null) count_c = "true";\r
- if (count_i==null) count_i = "1";\r
- // set length of outer array. if any\r
- var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;\r
- // loop through outer array\r
- for (var i=0; i<l; i++) {\r
- if (s==null && ss==null) {\r
- score += eval(score_i);\r
- if (eval(count_c)) count += eval(count_i);\r
- } else if (s) {\r
- score += eval(s) ? eval(score_i) : 0;\r
- if (eval(count_c)) count += eval(count_i);\r
- } else if (ss) {\r
- // set length of inner array, if any\r
- var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;\r
- // loop through inner array. checking inner condition\r
- for (var ii=0; ii<ll; ii++) {\r
- score += eval(ss) ? eval(score_i) : 0;\r
- if (eval(count_c)) count += eval(count_i);\r
- }\r
- }\r
- }\r
- if (count) {\r
- // get p(enalties) for JCross and JMatch (and JMix ?)\r
- if (window.Penalties) {\r
- score -= (Penalties - (hpFinished() ? 0 : 1));\r
- }\r
- // adjust count for Find-It 3a and 3b\r
- if (window.TotWrongChoices) {\r
- if (window.CheckText && !window.CheckAnswers) { // Find-It 3a\r
- // this seems a little odd, but will replicate behavior of CalculateScore()\r
- count = score + TotWrongChoices;\r
- } else {\r
- count += TotWrongChoices;\r
- }\r
- }\r
- score = Math.floor(100*score/count);\r
- if (score<0) { // just in case\r
- score = 0;\r
- }\r
- }\r
- return score;\r
-}\r
-function hpScore() {\r
- var x = ''; // score\r
- var hp = hpVersion();\r
- var t = hpQuizType();\r
- var v = hpQuizVersion();\r
- if (t==1) { // jbc\r
- if (v==3) x = hpScoreEngine(1, DoneStatus, "i>0 && a[i]=='0'"); // doesn't work\r
- else if (v==4) x = hpScoreEngine(1, DoneStatus, "a[i]==0"); // doesn't work\r
- else if (v==5 || v==6) x = hpScoreEngine("a[i][3]", Status, "a[i][3]");\r
- } else if (t==2) { // jcloze\r
- if (v==3 || v==4) x = hpScoreEngine("a[i]", Scores);\r
- else if (hp==5) x = hpScoreEngine("a[i][3]", State); // v==5 && v==6\r
- else if (hp==6) {\r
- var r = hpRottmeier();\r
- if (r==0) x = x = hpScoreEngine("a[i].ItemScore", State);\r
- else if (r==1) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapLocked"); // dropdown\r
- else if (r==2.1) x = hpScoreEngine(1, GapList, "a[i][1].ErrorFound"); // Find-It 3a\r
- else if (r==2.2) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapSolved"); // Find-It 3b\r
- }\r
- } else if (t==3) { // jcross\r
- if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");\r
- else if (v==4) x = hpScoreEngine(1, WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0)==a[i].charAt(0)");\r
- else if (v==5 || v==6) x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii]==G[i][ii]", "L[i][ii]");\r
- } else if (t==4) { // jmatch\r
- if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");\r
- else if (v==4) x = hpScoreEngine(1, Draggables, "a[i].correct=='1'");\r
- else if (v==5) x = hpScoreEngine(1, I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]==1");\r
- else if (v==6) x = hpScoreEngine(1, Status, "Status[i][0]==1");\r
- else if (v==5.1 || v==6.1) x = hpScoreEngine(1, D, "D[i][2]==D[i][1] && D[i][2]>0", "", "", "i<F.length");\r
- } else if (t==5) { // jmix\r
- // there was no v3 or v4 of JMix\r
- if (v==5 || v==6 || v==6.1) x = Math.floor(100*(Segments.length-Penalties)/Segments.length);\r
- } else if (t==6) { // jquiz\r
- if (hp==5) {\r
- if (v==3 || v==4) x = hpScoreEngine("a[i][4]/10", State, "a[i][0]==1");\r
- else if (v==5 || v==6) x = hpScoreEngine("a[i][4]/10", Status, "a[i][0]==1", "", "", "true", "1");\r
- } else if (hp==6) {\r
- if (v==6) x = hpScoreEngine("I[i][0]*a[i][0]", State, "a[i]&&a[i][0]>=0", "", "", "a[i]", "I[i][0]");\r
- }\r
- } else if (t==7) { // rhubarb\r
- if (v==6) {\r
- x = Math.floor(100*Correct/TotalWords);\r
- }\r
- } else if (t==8) { // sequitur\r
- if (v==6) {\r
- var myTotalPoints = TotalPoints - (hpFinished() ? 0 : (OptionsThisQ-1));\r
- x = Math.floor(100*ScoredPoints/myTotalPoints);\r
- }\r
- }\r
- return x; // result\r
-}\r
-function hpFinishedEngine(a, s, aa, ss) {\r
- // determine whether or not all quistions in a quiz are finished\r
- // a : outer array\r
- // s : condition, if any, on outer array\r
- // if true for any element in "a", the quiz is NOT finished\r
- // aa : inner array, if any\r
- // ss : condition, if any, on inner array\r
- // if true for any element in "aa", the quiz is NOT finished\r
- // the arrays "a" and "aa" may be passed as arrays or strings to be eval(uated)\r
- // the conditions "s" and "ss" are specified as strings to be eval(uated)\r
- // assume a positive result\r
- var x = true;\r
- // set length of outer array. if any\r
- var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;\r
- // loop through outer array\r
- for (var i=0; i<l; i++) {\r
- // do outer condition, if any\r
- if (s && eval(s)) x = false;\r
- // set length of inner array, if any\r
- var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;\r
- // loop through inner array. checking inner condition\r
- for (var ii=0; ii<ll; ii++) {\r
- if (ss && eval(ss)) x = false;\r
- }\r
- }\r
- return x;\r
-}\r
-function hpTimedOut() {\r
- // v5 uses "min" and "sec"\r
- // v6 uses Seconds\r
- return (typeof(self.Seconds)=='number' && Seconds==0) || (typeof(self.min)=='number' && min==0 && typeof(self.sec)=='number' && sec==0);\r
-}\r
-function hpFinished() {\r
- // assume false result\r
- var x = false; \r
- var hp = hpVersion();\r
- var t = hpQuizType();\r
- var v = hpQuizVersion();\r
- if (t==1) { // jbc\r
- if (v==3) x = hpFinishedEngine(DoneStatus, "i>0 && a[i]=='0'");\r
- else if (v==4) x = hpFinishedEngine(DoneStatus, "a[i]==0");\r
- else if (v==5 || v==6) x = hpFinishedEngine(Status, "a[i][0]==0");\r
- } else if (t==2) { // jcloze\r
- var r = hpRottmeier();\r
- if (r==1) x = hpFinishedEngine(GapList, "a[i][1].GapLocked==false"); // drop-down\r
- else if (r==2.1) x = hpFinishedEngine(GapList, "a[i][1].ErrorFound==false"); // find-it 3a\r
- else if (r==2.2) x = hpFinishedEngine(GapList, "a[i][1].GapSolved==false"); // find-it 3b\r
- else if (v==3 || v==4 || v==5 || v==6) x = hpFinishedEngine(I, "CheckAnswer(i)==-1");\r
- // also: else if (v==5 || v==6) x = hpFinishedEngine(State, "a[i][4]!=1")\r
- } else if (t==3) { // jcross\r
- if (v==3) x = hpFinishedEngine(document.Crossword.elements, "ConvertCase(is.mac?unescape(MacStringToWin(a[i].value)):a[i].value,1)!=Letters[i]");\r
- else if (v==4) x = hpFinishedEngine(WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0) != a[i].charAt(0)");\r
- else if (v==5 || v==6) x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii]!=G[i][ii]");\r
- } else if (t==4) { // jmatch\r
- if (v==3) x = hpFinishedEngine(CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex != a[i]");\r
- else if (v==4) x = hpFinishedEngine(Draggables, "a[i].correct!='1'");\r
- else if (v==5) x = hpFinishedEngine(I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]<1 && GetAnswer(i)!=I[i][3]");\r
- else if (v==6) x = hpFinishedEngine(Status, "Status[i][0]<1");\r
- else if (v==5.1 || v==6.1) x = hpFinishedEngine(D, "", F, "F[ii][1]==D[i][1]&&D[i][1]!=D[i][2]");\r
- } else if (t==5) { // jmix\r
- // there was no v3 or v4 of JMix\r
- if (v==5 || v==6 || v==6.1) x = !hpFinishedEngine(Answers, "a[i].join(',')=='" + GuessSequence.join(',') + "'");\r
- } else if (t==6) { // jquiz\r
- if (v==3 || v==4) x = hpFinishedEngine(State, "a[i][0]==0");\r
- else if (v==5 || v==6) {\r
- if (hp==5) x = hpFinishedEngine(Status, "a[i][0]<1");\r
- else if (hp==6) x = hpFinishedEngine(State, "a[i] && a[i][0]<0");\r
- }\r
- } else if (t==7) { // rhubarb\r
- if (v==6) x = hpFinishedEngine(DoneList, "a[i]==1");\r
- } else if (t==8) { // sequitur\r
- if (v==6) x = (CurrentNumber==TotalSegments || AllDone);\r
- }\r
- return x;\r
-}\r
-function hpObj(d, id) {\r
- return d.getElementById ? d.getElementById(id) : d.all ? d.all[id] : d[id];\r
-}\r
-function GetViewportHeight() {\r
- if (window.innerHeight) {\r
- return innerHeight;\r
- } else {\r
- if (hpIsStrict()) {\r
- return document.documentElement.clientHeight;\r
- } else {\r
- return document.body.clientHeight;\r
- }\r
- }\r
-}\r
-function hpIsStrict() {\r
- if (!window.hpStrictIsSet) {\r
- window.hpStrictIsSet = true;\r
- window.hpStrict = false;\r
- var s = document.compatMode;\r
- if (s && s=="CSS1Compat") { // ie6\r
- window.hpStrict = true;\r
- } else {\r
- var obj = document.doctype;\r
- if (obj) {\r
- var s = obj.systemId || obj.name; // n6 || ie5mac\r
- if (s && s.indexOf("strict.dtd") >= 0) {\r
- window.hpStrict = true;\r
- }\r
- }\r
- }\r
- }\r
- return window.hpStrict;\r
-}\r
-// **************\r
-// initialization\r
-// **************\r
-hpInterceptFeedback();\r
-hpInterceptHints();\r
-hpInterceptClues();\r
-hpInterceptChecks();\r
-function hpFindForm(formname, w) {\r
- if (w==null) w = self;\r
- var f = w.document.forms[formname];\r
- if (f==null && w.frames) {\r
- for (var i=0; i<w.frames.length; i++) {\r
- f = hpFindForm(formname, w.frames[i]);\r
- if (f) break;\r
- }\r
- }\r
- return f;\r
-}\r
-function Finish(quizstatus) {\r
- var mark = hpScore();\r
- window.hpForm = hpFindForm('store');\r
- if (hpForm) { // LMS\r
- hpForm.starttime.value = getTime(Start_Time);\r
- hpForm.endtime.value = getTime();\r
- hpForm.mark.value = mark;\r
- hpForm.detail.value = '<?xml version="1.0"?><hpjsresult><fields>'+GetQuestionDetails()+'</fields></hpjsresult>';\r
- if (hpForm.status) {\r
- if (!quizstatus) {\r
- // 4=completed, 3=abandoned, 2=timed-out or 1=in-progress\r
- quizstatus = hpFinished() ? 4 : hpTimedOut() ? 2 : 1;\r
- }\r
- hpForm.status.value = quizstatus;\r
- }\r
- if (!window.hpQuizResultsSent) {\r
- if (hpForm.status && quizstatus==4) {\r
- window.hpQuizResultsSent = true;\r
- }\r
- if (quizstatus==4) { // completed\r
- // wait 2 seconds for student to see feedback\r
- setTimeout("hpForm.submit();", 2000);\r
- } else {\r
- hpForm.submit();\r
- }\r
- }\r
- } else if (hpFinished()) {\r
- SendAllResults(mark);\r
- }\r
-}\r
-// create form to send results\r
-if (DB[7] && DB[8] && !is_LMS()) { \r
- ResultForm = ''\r
- + '<html><body>'\r
- + '<form name="Results" action="" method="post" enctype="x-www-form-encoded">'\r
- + hpHiddenField('recipient', '')\r
- + hpHiddenField('subject', '')\r
- + hpHiddenField('Exercise', '')\r
- + hpHiddenField('realname', '')\r
- + hpHiddenField('Score', '')\r
- + hpHiddenField('Start_Time', '')\r
- + hpHiddenField('End_Time', '')\r
- + hpHiddenField('title', 'Thanks!')\r
- + '</form>'\r
- + '</body></html>'\r
- ;\r
-}\r
-// reassign the StartUp function\r
-var p = getPrompt(window.GetUserName || window.StartUp);\r
-var c = getStartUpCode(window.StartUp);\r
-if (p && c) {\r
- window.StartUp = new Function('QuizLogin("' + p + '")');\r
- window.StartQuiz = new Function(c);\r
- // "QuizLogin" finshes by calling "StartQuiz"\r
-}\r
-// reassign the SendResults function\r
-window.SendResults = SendAllResults;\r
-// set start time\r
-var Start_Time = new Date();\r
-//-->\r
+<!--
+// PLEASE NOTE that this version is more recent than the incorrectly
+// numbered v6.1, dated 2003.11.17. From now on, version numbers will
+// follow those of Hot Potatoes.
+/* hot-potatoes.js (v6.0.4.0 - 2005.02.18)
+ * =======================================
+ * by Gordon Bateson, February 2003
+ * Copyright (c) 2003 Gordon Bateson. All Rights Reserved.
+ *
+ * You are hereby granted a royalty free license to use or modify this
+ * software provided that this copyright notice appears on all copies.
+ *
+ * This software is provided "AS IS" without a warranty of any kind.
+ *
+ * Documentation and downloads may be available from:
+ * http://www.kanazawa-gu.ac.jp/~gordon/research/hot-potatoes/
+ */
+// This JavaScript library modifies the SendResults and StartUp functions
+// used by hotpot v5 and v6, so that more (or less!) details about the
+// student can be input, and more details of a quiz's questions and answers
+// can be submitted to the server when the quiz is finished
+// If the arrays below (Login, DB, JBC, ...) are set BEFORE calling this
+// script, they will NOT be overwritten. Any array that is not set, will
+// use the defaults below. This is useful if you want to use different
+// settings for different quizzes.
+// ************
+// Login Screen
+// ************
+if (window.Login==null) {
+ Login = new Array();
+ Login[0] = true; // Show prompt for user name
+ // This can also be a string of user names ...
+ // Login[0] = "Guest,Peter,Paul,Mary,Webmaster";
+ // or an array of user names (and on-screen texts) (and passwords) ...
+ // Login[0] = new Array("Guest", "001,Peter,xxxx", "002,Paul,yyyy", "003,Mary,zzzz", "Webmaster");
+ // and can also be written as ...
+ // Login[0] = new Array(
+ // new Array("Guest"),
+ // new Array("001", "Peter", "xxxx"),
+ // new Array("002", "Paul", "yyyy"),
+ // new Array("003", "Mary", "zzzz"),
+ // new Array("Webmaster")
+ // );
+ Login[1] = true; // Show prompt for student's UserID
+ // If there is no password prompt (i.e. Logon[3] is false), this value
+ // will be checked against the password information, if any, in Login[0]
+ Login[2] = false; // Show prompt for student's email
+ Login[3] = false; // Show prompt for quiz password, and check this value against
+ // the password information, if any, in Login[0]
+ // This can also be a string required to start the quiz ...
+ // Login[3] = "password";
+ Login[4] = true; // Show prompt for the cookie expiry date
+ // If false, cookies expire at the end of the current session
+ Login[5] = "guest,webmaster"
+ // guest user names (case insensitive) ...
+ // Login[5] = "guest,webmaster";
+ // These users do NOT need to fill in other login fields
+ // and their quiz results are NOT added to the database
+ // the Login prompts and error messages
+ // are defined in the MSG array (see below)
+}
+// *********
+// Database (for use with BFormMail)
+// *********
+if (window.DB==null) {
+ DB = new Array();
+ DB[0] = true; // append form fields to database on server
+ // If you are NOT using BFormMail's database feature,
+ // set DB[0]=false, and you can then safely ignore DB[1 to 5]
+ DB[1] = "/home/gordon/public_html/cgi/hot-potatoes-data";
+ // append_db folder path (no trailing slash)
+ // Can be either an absolute path e.g. "/home/gordon/public_html/cgi/hot-potatoes-data"
+ // or a relative (to CGI bin) path e.g. "hot-potatoes-data"
+ DB[2] = "hot-potatoes";
+ // append_db file name (no extension)
+ // If left blank, the quiz file name, without extension, will be used
+ // i.e. each quiz will have its results stored in a different file.
+ // If filled in, this file will store the results for ALL quizzes.
+ // Database files and folders must be set up BEFORE running the quiz
+ // must have appropriate access privileges (on Unix, use "chmod 666").
+ DB[3] = ""; // append_db extension (if left blank, ".txt" will be used)
+ DB[4] = ""; // db_fields (if left blank, ALL quiz fields will be sent)
+ DB[5] = ""; // db_delimiter (if left blank, tab will be used)
+ DB[6] = "REMOTE_ADDR,HTTP_USER_AGENT";
+ // env_report ('REMOTE_ADDR','HTTP_USER_AGENT' and a few others)
+ // for a complete description of these fields are, see ...
+ // http://www.infosheet.com/stuff/BFormMail.readme
+ // Switches DB[7] and DB[8] force the settings in the ResultForm
+ // In v5 and v6 quizzes, these settings wil be override those in the original quiz
+ // If the quiz results are to be sent to an LMS (via the "store" form)
+ // then switches DB[7] and DB[8] are not used
+ DB[7] = ''; // URL of form processing script
+ // e.g. http://www.kanazawa-gu.ac.jp/~gordon/cgi/bformmail.cgi
+ DB[8] = ''; // email address to which results should be sent
+ // e.g. gordon@kanazawa-gu.ac.jp
+}
+// By default the quiz's question's scores will be returned.
+// If you want more detailed information, set the flags below:
+// ********
+// JBC
+// ********
+if (window.JBC==null) {
+ JBC = new Array();
+ JBC[0] = true; // show separator line between answers on email
+ JBC[1] = true; // show number of attempts to answer question
+ JBC[2] = true; // show question texts
+ JBC[3] = true; // show right answer(s)
+ JBC[4] = true; // show wrong answer(s)
+ JBC[5] = true; // show ignored answer(s)
+ JBC[6] = false; // show answer as text (false) or number (true)
+}
+// JBC quizzes use the global variables 'I' and 'Status'
+// I : an array of JBC_QUESTIONs (one for each question)
+// JBC_QUESTION :
+// [0] : question text
+// [1] : array of JBC_ANSWERs (one for each answer)
+// [2] : single/multi flag
+// 0 : single answer (using 'button')
+// 1 : multiple answers (using 'checkbox')
+// JBC_ANSWER :
+// [0] : answer text
+// [1] : answer feedback
+// [2] : correct answer flag
+// 0 : this is NOT the correct answer
+// 1 : this is the correct answer
+// Status : an array of JBC_QUESTION_STATUSes
+// JBC_QUESTION_STATUS:
+// [0] : correctly answered yet flag
+// 0 : this question has NOT been correctly answered
+// 1 : this question has been correctly answered
+// [1] : array of JBC_ANSWER_STATUSes (one for each answer)
+// '0' : initial value
+// 'R' : single answer question was answered 'R'ight
+// 'W' : single answer question was answered 'W'rong
+// 'C' : multiple answer question's checkbox was 'C'hecked
+// 'U' : multiple answer question's checkbox was 'U'nchecked
+// [2] : number of times this question has been wrongly answered
+// [3] : score (out of 1) for this question (maybe undefined on HP<5.5)
+// 0 : not correct yet
+// 0<[3]<1 : correct but only after [2] wrong attempts
+// 1 : correct first time (bravo!)
+// N.B. score = (numberOfAnswers - numberofWrongTries) / numberOfAnswers
+// ********
+// JCloze
+// ********
+if (window.JCloze==null) {
+ JCloze = new Array();
+ JCloze[0] = true; // show separator line between answers on email
+ JCloze[1] = true; // show student's correct answer
+ JCloze[2] = true; // show other correct answer(s), if any
+ JCloze[3] = true; // show wrong answer(s), if any (NOT available for v5)
+ JCloze[4] = false; // show number of hints + checks (legacy field, replaced by [7]+[9])
+ JCloze[5] = false; // show if clue was asked for or not (legacy field, replaced by [8])
+ JCloze[6] = true; // show clue
+ JCloze[7] = true; // show number of hints (=next letter requests)
+ JCloze[8] = true; // show number of clues
+ JCloze[9] = true; // show number of checks
+}
+// JCloze quizzes use the global variables 'I' and 'State'
+// I : array of JCLOZE_ANSWERs
+// JCLOZE_ANSWER :
+// [0] : (unused)
+// [1] : array of JCLOZE_ANSWER_TEXTs
+// [2] : clue for this answer
+// JCLOZE_ANSWER_TEXT :
+// [0] : array (seems unnecessary, just the text would be enough?)
+// [0] : text of possible answer
+// State : array of JCLOZE_ANSWER_STATEs
+// JCLOZE_ANSWER_STATE (v5) :
+// [0] : clue asked for or not
+// [1] : number of hints (show next letter) and penalties ('check' an incorrect answer)
+// [2] : length of answer matched
+// [3] : score for this item
+// [4] : already answered correctly
+// [5] : answer entered in text box (right or not)
+// JCLOZE_ANSWER_STATE (v6)
+// this.ClueGiven = false;
+// this.HintsAndChecks = 0;
+// this.MatchedAnswerLength = 0;
+// this.ItemScore = 0;
+// this.AnsweredCorrectly = false;
+// this.Guesses = new Array(); last guess is correct answer
+// ********
+// JCross
+// ********
+if (window.JCross==null) {
+ JCross = new Array();
+ JCross[0] = true; // show separator line between answers on email
+ JCross[1] = true; // show number of penalties (hints or checks before complete)
+ JCross[2] = true; // show number of letters
+ JCross[3] = true; // show correct answers
+ JCross[4] = true; // show clues
+ JCross[5] = true; // show wrong answers
+ JCross[6] = true; // show if clue was asked for or not
+ JCross[7] = true; // show number of hints (=next letter requests)
+ JCross[8] = true; // show number of checks
+ // there are no "ignored" answers for JCross quizzes
+}
+// JCross quizzes use the following global variables:
+// L : letters (of correct answers)
+// C : clue numbers (CL in v6)
+// G : guesses
+// 'L', 'C' ('CL') and 'G' are all 2-dimensional arrays (rows x cols)
+//
+// v5 quizzes additionally use the following single-dimension arrays
+// A : clues for across (horizontal) words
+// D : clues for down (vertical) words
+// N.B. form is only sent when all answers are correct so
+// you can't find out what 'wrong' answers were entered
+// ********
+// JMatch
+// ********
+if (window.JMatch==null) {
+ JMatch = new Array();
+ JMatch[0] = true; // show separator line between answers on email
+ JMatch[1] = false; // show number of penalties (= total number of checks)
+ JMatch[2] = true; // show LHS texts (the question)
+ JMatch[3] = true; // show correct answers
+ JMatch[4] = true; // show wrong answers
+ JMatch[5] = true; // show checks (per match) [empty or unchanged RHS are not counted]
+ // JMatch has no "clue" or "hint" buttons
+ // there cannot be any "ignored" answers
+}
+// v5 JMatch quizzes use the global variables 'I' and 'Status' (and 'RItems')
+// v6 JMatch quizzes use only 'Status'
+// v6+ JMatch quizzes use 'F' and 'D' (see below)
+// I : an array of JMATCH_PAIRs (one for each pair)
+// JMATCH_PAIR :
+// [0] : LHS text
+// [1] : RHS text
+// [2] : fixed (=not jumbled) flag
+// 0 : not fixed
+// 1 : fixed
+// [3] : index in drop down list selection
+// Status : an array of JMATCH_PAIR_STATUSes
+// JMATCH_PAIR_STATUS:
+// [0] : correctly matched yet flag
+// 0 : this pair has NOT been correctly matched
+// 1 : this pair has been correctly matched
+// [1] : number of times this item has been wrongly matched
+// v6 quizzes only
+// [2] : id of original SELECT element containing possible matches
+// Note that after matching, this SELECT is removed, so don't try looking for it :-)
+// v6+ JMatch quizzes use the global variables 'F' and 'D'
+// F : array of JMATCH_FIXED_ITEMs
+// JMATCH_FIXED_ITEM:
+// [0] : text
+// [1] : tag
+// D : array of JMATCH_DRAGGABLE_ITEMs
+// JMATCH_DRAGGABLE_ITEM
+// [0] : text
+// [1] : tag of the F item to which it SHOULD be dragged
+// [2] : tag of the F item to which it was dragged (initally 0)
+// N.B. form is only sent when all answers are correct so
+// you can't find out what 'wrong' answers were entered
+// ********
+// JMix
+// ********
+if (window.JMix==null) {
+ JMix = new Array();
+ JMix[0] = true; // show separator line between answers on email
+ JMix[1] = false; // show number of wrong guesses (replaced by JMix[5])
+ JMix[2] = true; // show right answer
+ JMix[3] = true; // show wrong answer, if any
+ JMix[4] = false; // show answer as text (false) or number (true)
+ JMix[5] = true; // show number of checks
+ JMix[6] = true; // show number of hints (=show next word)
+}
+// JMix quizzes use the global variables
+// 'Segments', 'GuessSequence' and 'Penalties'
+// Segments : array of JMix_QUESTIONs
+// JMix_QUESTION:
+// [0] : text
+// [1] : order in sequence
+// [2] : used flag
+// GuessSequence : array of 'order in sequence' numbers
+// Penalties : number of incorrect guesses
+// ********
+// JQuiz
+// ********
+if (window.JQuiz==null) {
+ JQuiz = new Array();
+ JQuiz[0] = true; // show separator line between answers on email
+ JQuiz[1] = true; // show question text
+ JQuiz[2] = true; // show student's correct answer(s)
+ JQuiz[3] = false; // show wrong and ignored answer(s) (legacy field superceded by [8] & [9])
+ JQuiz[4] = true; // show number of hints requested
+ JQuiz[5] = false; // show number of checks of incorrect answers (legacy field superceded by [12])
+ // HP6 v6 quizzes only
+ JQuiz[6] = false; // show answer value (false) or A,B,C... index (true)
+ JQuiz[7] = true; // show all students answers
+ JQuiz[8] = true; // show student's wrong answers
+ JQuiz[9] = true; // show ignored answers (not relevant for multi-select questions)
+ JQuiz[10] = true; // show score weightings
+ JQuiz[11] = true; // show question type
+ JQuiz[12] = true; // show number of checks (if true, then JQuiz[5] of will be ignored)
+ JQuiz[13] = true; // show number of times ShowAnswer button was pressed (usually 0 or 1)
+}
+// v5 JQuiz quizzes use the global variables 'I' and 'Status'
+// I : array of JQUIZ_ANSWERs
+// JQUIZ_ANSWER :
+// [0] : question text
+// [1] : array of JQUIZ_ANSWER_TEXTs (one for each answer)
+// JQUIZ_ANSWER_TEXT :
+// [0] : array (seems unnecessary, just the text would be enough?)
+// [0] : text of possible answer
+// Status : array of JQUIZ_ANSWER_STATEs
+// JQUIZ_ANSWER_STATE :
+// [0] : question done or not
+// [1] : number of wrong checks
+// [2] : number of hints asked for
+// [3] : student's answer
+// [4] : score for this question
+// v6 JQuiz quizzes use the global variables 'I' and 'State'
+// I : array of JQUIZ_QUESTIONs
+// JQUIZ_QUESTION :
+// [0] : weighting
+// [1] : ?? (always set to '')
+// [2] : question type
+// '0'=multiple-choice, '1'=short-answer, '2'=hybrid, '3'=multi-select
+// [3] : array of JQUIZ_ANSWERSs (one for each possible answer)
+// JQUIZ_ANSWER :
+// [0] : answer value
+// [1] : feedback text
+// [2] : correct answer flag (1=a correct answer, 0=a wrong answer)
+// [3] : weighted score (as percentage) if correct
+// [4] : flag (usually set to 1, but for hybrid answers that are not
+// to be included in multiple choice options, it is set to 0)
+// State : array of JQUIZ_QUESTION_STATEs
+// JQUIZ_QUESTION_STATE :
+// [0] : score (-1 shows not done yet)
+// [1] : array showing on which number try each JQUIZ_ANSWER was selected
+// [2] : number of attempts at this question
+// [3] : total of weighted scores of correct answers that were selected
+// i.e. each time a correct answer is selected,
+// its JQUIZ_ANSWER[3] weighting is added to this total
+// so when all the correct answers have been selected, this will be 100
+// [4] : penalties incurred for hints (score is set to zero if >= 1)
+// [5] : - for multiple choice, short-answer and hybrid questions, this is a
+// comma-delimited list showing order in which answers were chosen
+// - for multi-select fields, this is bar-delimted ('|') list of settings
+// showing whether each checkbox was selected ('Y') on not ('N') when the
+// 'Check' button was clicked. The final item in the list will be the
+// settings for the correct answer.
+// N.B. JBC, JMatch(v5) and JQuiz(v5) all use global variables 'I' and 'Status'
+// JBC : I[0].length==3 && !window.RItems
+// JQuiz(v5) : I[0].length==2
+// JMatch(v5) : I[0].length==4 && window.RItems
+// N.B. JCloze(v5+6) and JQuiz(v6) both use global variables 'I' and 'State'
+// JCloze (v5) : I[0].length==3 && State[0].Guesses==null
+// JCloze (v6) : I[0].length==3 && State[0].Guesses!=null
+// JQuiz (v6) : I[0].length==4
+// **********
+// Rhubarb
+// **********
+if (window.Rhubarb==null) {
+ Rhubarb = new Array();
+ Rhubarb[0] = true; // show correct words (so far)
+ Rhubarb[1] = true; // show correct words as count (true) or list (false)
+ Rhubarb[2] = true; // show wrong words
+ Rhubarb[3] = false; // show wrong words as count (true) or list (false)
+ Rhubarb[4] = false; // show ignored words (not implemented yet)
+ Rhubarb[5] = true; // show hints
+}
+// **********
+// Sequitur
+// **********
+if (window.Sequitur==null) {
+ Sequitur = new Array();
+ Sequitur[0] = true; // show count of correct button clicks
+ Sequitur[1] = true; // show count of wrong button clicks
+}
+// **********
+// Messages
+// **********
+if (window.MSG==null) {
+ MSG = new Array();
+ // Login prompts
+ MSG[0] = 'Name';
+ MSG[1] = 'ID';
+ MSG[2] = 'Email';
+ MSG[3] = 'Password';
+ MSG[4] = 'Cookies';
+ // Login buttons
+ MSG[5] = 'Start the Quiz';
+ MSG[6] = 'Cancel';
+ // Cookie menu options (only used if Login[4] is true)
+ MSG[7] = 'keep for this session only';
+ MSG[8] = 'keep for one day';
+ MSG[9] = 'keep for one month';
+ MSG[10] = 'do NOT keep cookies';
+ // Login error messages
+ MSG[11] = 'Sorry, you were unable to login. Please try again later.';
+ MSG[12] = 'Please fill in all the information.';
+ MSG[13] = 'Incorrect Password. Please try again.';
+ MSG[14] = 'Incorrect ID. Please try again.';
+ MSG[15] = 'Email address does not appear to be valid.';
+ // day and month names (used in Start_Time and End_Time)
+ MSG[16] = new Array('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+ MSG[17] = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+ // enable popups
+ MSG[18] = 'Please enable pop-up windows on your browser.';
+ // browser specific instuctions on how to enable popup windows
+ var n = navigator;
+ var s = n.userAgent.toLowerCase();
+ if (n.appName=='Netscape' && s.indexOf('gecko')>=0) {
+ // Netscape 6 and 7
+ MSG[18] += '\n\n' + 'Edit->Preferences, ' + (s.indexOf('mac')>=0 ? 'Advanced->Scripts & Plugins' : 'Privacy & Security->Popup Window Controls');
+ } else if (s.indexOf('safari')>=0) {
+ // Safari
+ MSG[18] += '\n\n' + 'on Safari menu, uncheck "Block Pop-Up Windows"';
+ } else if (s.indexOf('firebird')>=0) {
+ // Firebird
+ MSG[18] += '\n\n' + 'Preferences->Web Features, uncheck "Block Pop-Up Windows"';
+ } else if (s.indexOf('msie 6')>=0) {
+ // IE 6 (WinXP.SP2)
+ MSG[18] += '\n\n' + 'Tools->Pop-up Blocker->Turn Off Pop-up Blocker';
+ }
+}
+//if (window.FEEDBACK==null) {
+// 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] = ''; // 'email@somewhere.com>' [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[8] = ''; // 'Message'
+// FEEDBACK[10] = ''; // 'Close this window' [formmail only]
+//}
+// **********
+// HP array
+// **********
+HP = new Array();
+for (var i=0; i<=8; i++) {
+ HP[i] = new Array();
+}
+// indexes for the HP array (makes the code further down easier to read)
+_score = 0;
+_weight = 1;
+_correct = 2;
+_wrong = 3;
+_unused = 4;
+_hints = 5;
+_clues = 6;
+_checks = 7;
+_guesses = 8;
+// *************
+// Server Fields
+// *************
+if (window.ServerFields==null) {
+ ServerFields = new Array();
+ // these fields will be added to the ResultForm and submitted to the CGI script on the server.
+ // 'Sort', 'return_link_title', 'return_link_url' and 'print_blank_fields' are useful for formmail
+ // override the HP setting of sort fields (forces ALL fields to be displayed)
+ ServerFields[0] = new Array('sort', '');
+ // add link to close pop-up results window
+ ServerFields[1] = new Array('return_link_title', 'Close this window');
+ ServerFields[2] = new Array('return_link_url', 'javascript:self.close()');
+ // make sure zero values are printed
+ ServerFields[3] = new Array('print_blank_fields', 'yes');
+ // you can also set other fields for your customized CGI script
+ // e.g. adding a server defined start time (instead of a client defined start time)
+ // ServerFields[4] = new Array('serverStartTime', '<?php echo date("Y-m-d H:i:s") ?>');
+}
+// *********************
+// Login screen
+// (not required by LMS)
+// *********************
+function QuizLogin(LoginPrompt) {
+ if (!is_LMS() && (Login[0] || Login[1] || Login[2] || Login[3])) {
+ var html = ''
+ + '<html>'
+ + '<head></head>'
+ + '<body bgColor="#cccccc" onLoad="opener.setFocus(self)">'
+ + '<form onSubmit="'
+ + 'self.ok=true;'
+ + 'self.expiry=null;'
+ ;
+ if (Login[4]) { // cookie expiry
+ html += "opener.checkOK(self,'CookieExpiry');";
+ }
+ if (Login[0]) { // user name
+ html += "opener.checkOK(self,'UserName');";
+ }
+ if (Login[1]) { // user ID
+ html += "opener.checkOK(self,'UserID');";
+ }
+ if (Login[2]) { // user email
+ html += "opener.checkOK(self,'UserEmail');";
+ }
+ if (Login[3]) { // quiz password
+ html += "opener.checkOK(self,'Password');";
+ }
+ html += 'if(ok){'
+ + 'opener.StartQuiz();'
+ + 'self.close();'
+ + '}else{'
+ + 'if(isNaN(self.tries))self.tries=0;'
+ + 'self.tries++;'
+ + 'if(self.tries<3){'
+ + 'opener.setFocus(self);'
+ + '}else{'
+ + "alert(opener.MSG[11]);"
+ + 'opener.goBack();'
+ + 'self.close();'
+ + '}'
+ + '}'
+ + 'return false;'
+ + '">'
+ ;
+ html += '<table>'
+ + '<caption>' + LoginPrompt + '</caption>';
+ ;
+ if (Login[0]) { // user name
+ var v = getCookie(self, 'UserName');
+ html += '<tr>'
+ + '<th align=right nowrap>' + MSG[0] + ' :</th>'
+ + '<td>'
+ ;
+ if (typeof(Login[0])=='boolean') { // text box
+ html += '<input type=text name=UserName value="' + v + '">';
+ } else { // drop down menu of names
+ // pattern to match commas and white space
+ var comma = (window.RegExp) ? new RegExp('\\s*,\\s*') : ',';
+ // convert list of names to array, if necessary
+ if (typeof(Login[0])=='string') {
+ Login[0] = Login[0].split(comma);
+ }
+ html += '<select name=UserName size=1>'
+ + '<option value=""></option>'
+ ;
+ for(var i=0; i<Login[0].length; i++) {
+ // convert name details to array if nececount_cary
+ if (typeof(Login[0][i])=='string') {
+ Login[0][i] = Login[0][i].split(comma);
+ }
+ html += makeOption(Login[0][i][0], v, Login[0][i][1]);
+ }
+ html += '</select>';
+ }
+ html += '</td>'
+ + '</tr>'
+ ;
+ }
+ if (Login[1]) { // user ID
+ var v = getCookie(self, 'UserID');
+ html += '<tr><th align=right nowrap>' + MSG[1] + ' :</th><td><input type=text name=UserID value="' + v + '"></td></tr>';
+ }
+ if (Login[2]) { // user email
+ var v = getCookie(self, 'UserEmail');
+ html += '<tr><th align=right nowrap>' + MSG[2] +' :</th><td><input type=text name=UserEmail value="' + v + '"></td></tr>';
+ }
+ if (Login[3]) { // quiz password
+ var v = getCookie(self, 'Password');
+ html += '<tr><th align=right nowrap>' + MSG[3] + ' :</th><td><input type=password name=Password value="' + v + '"></td></tr>';
+ }
+ if (Login[4]) { // cookie lifespan
+ var v = getCookie(self, 'CookieExpiry');
+ html += '<tr>'
+ + '<th align=right nowrap>' + MSG[4] + ' :</th>'
+ + '<td>'
+ + '<select name="CookieExpiry" size=1>'
+ + makeOption('session', v, MSG[7])
+ + makeOption('day', v, MSG[8])
+ + makeOption('month', v, MSG[9])
+ + makeOption('never', v, MSG[10])
+ + '</select>'
+ + '</td>'
+ + '</tr>'
+ ;
+ }
+ html += '<tr>'
+ + '<th> </th>'
+ + '<td nowrap>'
+ + '<input type=submit value="' + MSG[5] + '"> '
+ + '<input type=button value="' + MSG[6] + '" onClick="opener.goBack();self.close();">'
+ + '</td>'
+ + '</tr>'
+ + '</table></form></body></html>'
+ ;
+ // set height of Login Window
+ var m = navigator.userAgent.indexOf('Mac')>=0;
+ var h = (m ? 80 : 100);
+ for (var i=0; i<5; i++) h += (Login[i] ? (m ? 20 : 25) : 0);
+ // open up a new window
+ if (!openWindow('', '', (m ? 320 : 300), h, 'RESIZABLE', html)) {
+ alert(MSG[18]); // unable to open popup window
+ }
+ } else { // no Login required
+ window.UserName = window.UserID = window.UserEmail = window.Password = '';
+ window.StartQuiz();
+ }
+ return true;
+}
+function makeOption(value, v, txt) {
+ return '<option value="' + value + '"' + (value==v ? ' SELECTED' : '') + '>' + (txt ? txt : value) + '</option>';
+}
+function setFocus(w) {
+ w.focus(); // bring window to the front
+ var obj = w.document.forms[0].elements;
+ for(var i=0; i<obj.length; i++) {
+ var v = getValue(w, i);
+ if (v=='' || obj[i].type=='submit') {
+ obj[i].focus();
+ break;
+ }
+ }
+}
+function checkOK(w, n){
+ var v = getValue(w, n, true);
+ if (v || (n!='UserName' && isGuest())) {
+ if (n=='CookieExpiry') setCookieExpiry(w, v);
+ setCookie(self, n, v, w.expiry);
+ if (n!='CookieExpiry') eval('self.' + n + '=v');
+ } else {
+ if (w.ok) alert(MSG[12]);
+ w.ok = false;
+ }
+}
+function getValue(w, n, flag) {
+ var obj = w.document.forms[0].elements[n];
+ var TYPE = obj.type.toUpperCase(); // required for ns4 (win)
+ if (obj.options && TYPE.indexOf('SELECT')>=0){
+ var v = obj.options[obj.selectedIndex].value;
+ } else {
+ var v = obj.value;
+ }
+ if (flag) {
+ var msg = '';
+ if (n=='Password' || (n=='UserID' && !Login[3])) {
+ var pwd = getPassword(w);
+ if (pwd && v!=pwd) msg = MSG[n=='Password' ? 13 : 14];
+ }
+ if (n=='UserEmail' && window.RegExp) {
+ var r = '(\\w|-)+';
+ r = r + '(\\.' + r + ')';
+ r = new RegExp('^(' + r + '*)@(' + r + '+)$');
+ if (v.match(r)==null) msg = MSG[15];
+ }
+ if (msg) {
+ obj.value = v = '';
+ if (w.ok) alert(msg);
+ w.ok = false;
+ }
+ }
+ return v;
+}
+function getPassword(w) {
+ var pwd = '';
+ if (Login[3] && typeof(Login[3])=='string') {
+ pwd = Login[3];
+ } else if ((Login[3] || Login[1]) && typeof(Login[0])=='object') {
+ var username = getValue(w, 'UserName');
+ for(var i=0; i<Login[0].length; i++) {
+ if (username==Login[0][i][0]) {
+ pwd = Login[0][i][2];
+ break;
+ }
+ }
+ }
+ return pwd;
+}
+function setCookieExpiry(w, v) {
+ if (v=='never'){
+ w.expiry = new Date('Thu, 01-Jan-70 00:00:01 GMT');
+ } else if (v=='day' || v=='month') {
+ var ms = (v=='month' ? 31 : 1) * 60 * 60 * 24 * 1000;
+ w.expiry = new Date((new Date()).getTime() + ms);
+ }
+}
+function setCookie(w, name, value, expires, path, domain, secure) {
+ if (name) w.document.cookie = ''
+ + 'HP_' + name + "=" + escape(value)
+ + (expires ? "; expires=" + expires.toGMTString() : "")
+ + (path ? "; path=" + path : "")
+ + (domain ? "; domain=" + domain : "")
+ + (secure ? "; secure" : "")
+ ;
+}
+function getCookie(w, n) {
+ var c = w.document.cookie;
+ var i = c.indexOf('HP_' + n + '=');
+ var j = (i<0) ? -1 : c.indexOf(';', (i += n.length + 4));
+ return (i<0) ? '' : unescape(c.substring(i, ((j<0) ? c.length : j)));
+}
+function goBack(w) {
+ if (w==null) w = self; // default
+ if (w.history.length) w.history.back();
+}
+function openWindow(url, name, width, height, attributes, html) {
+ // set height, width and attributes
+ if (window.screen && width && height) {
+ var W = screen.availWidth;
+ var H = screen.availHeight;
+ width = Math.min(width, W);
+ height = Math.min(height, H);
+ attributes = ''
+ + (attributes ? (attributes+',') : '')
+ + 'WIDTH='+width+',HEIGHT='+height
+ ;
+ }
+ // create global hpWindows object, if necessary
+ if (!window.hpWindows) window.hpWindows = new Array();
+ // initialize window object
+ var w = null;
+ // has a window with this name been opened before?
+ if (name && hpWindows[name]) {
+ // http://www.webreference.com/js/tutorial1/exist.html
+ if (hpWindows[name].open && !hpWindows[name].closed) {
+ w = hpWindows[name];
+ w.focus();
+ } else {
+ hpWindows[name] = null;
+ }
+ }
+ // check window is not already open
+ if (w==null) {
+ // workaround for "Access is denied" errors in IE when offline
+ // based on an idea seen at http://www.devshed.com/Client_Side/JavaScript/Mini_FAQ
+ var ie_offline = (document.all && location.protocol=='file:');
+ // try and open the new window
+ w = window.open((ie_offline ? '' : url), name, attributes);
+ // check window opened OK (user may have prevented popups)
+ if (w) {
+ // center the window
+ if (window.screen && width && height) {
+ w.moveTo((W-width)/2, (H-height)/2);
+ }
+ // add content, if required
+ if (html) {
+ with (w.document) {
+ clear();
+ open();
+ write(html);
+ close();
+ }
+ } else if (url && ie_offline) {
+ w.location = url;
+ }
+ if (name) hpWindows[name] = w;
+ }
+ }
+ return w;
+}
+// *********************
+// Send results by email
+// (not required by LMS)
+// *********************
+function SendAllResults(Score) {
+ // check this quiz is not generated by a LMS
+ if (!is_LMS()) {
+ // add flat file database details to the results form
+ AddDatabaseDetailsToResultForm();
+ // add student details to the results form
+ AddStudentDetailsToResultForm();
+ // add question details to the results form
+ AddQuestionDetailsToResultForm();
+ // add server fields, if any, to results form
+ AddServerFieldsToResultForm();
+ // change "method" of form, because "get" only allows 512 byts of data
+ ResultForm = replaceLast('method="get"', 'method="post"', ResultForm);
+ // create results window and form
+ var w = openWindow('', '', 500, 400, 'RESIZABLE,SCROLLBARS,LOCATION', ResultForm);
+ // check window opened OK (user may have prevented popups)
+ if (w) {
+ // get shortcut to form object
+ var form = w.document.forms[0];
+ // update some important field values
+ form.Score.value = Score + '%';
+ form.realname.value = UserName;
+ form.Start_Time.value = getTime(Start_Time);
+ form.End_Time.value = getTime();
+ // force email subject and Exercise title
+ form.subject.value = document.title;
+ form. Exercise.value = document.title;
+ // update DB fields, if required
+ if (DB[0] && !isGuest()) set_db_fields(form);
+ if (DB[7]) form.action = DB[7];
+ if (DB[8]) form.recipient.value = DB[8];
+ // if this is a Netscape browser, check if the referer will be set OK
+ if (navigator.appName=='Netscape' && (location.protocol=='file:' || navigator.userAgent.indexOf('Netscape6')>=0)) {
+ // ns4 and ns7 set referer to 'file:// ...' when running a quiz offline
+ // ns6.2 (at least) always sets referer to 'about:blank'
+ // Netscape's setting of referer can cause BFormMail
+ // to reject the form, so encode the form data as a URL
+ var url = form.action;
+ var obj = form.elements;
+ for (var i=0; i<obj.length; i++) {
+ var v = escape(obj[i].value);
+ v = v.replace((new RegExp('\\+', 'g')), '%2B');
+ url += (i==0 ? '?' : '&') + obj[i].name + '=' + v;
+ }
+ w.location.href = url;
+ } else { // browser can POST form ok
+ form.submit();
+ }
+ } else { // unable to open popup window
+ alert(MSG[18]);
+ }
+ } // end if LMS
+}
+function isGuest() {
+ // check username is not a "guest" user
+ var flag = false;
+ var n = getCookie(self, 'UserName').toLowerCase();
+ if (n) {
+ // convert list of user names to array, if necessary
+ if(typeof(Login[5])=='string') {
+ Login[5] = Login[5].split(',');
+ }
+ for(var i=0; i<Login[5].length; i++) {
+ if (n==Login[5][i].toLowerCase()) {
+ flag = true;
+ break;
+ }
+ }
+ }
+ return flag;
+}
+function set_db_fields(form) {
+ // update list of DB fields, if required
+ if (DB[4]=='' && window.RegExp) {
+ // add administration fields
+ var db_fields = ''
+ + 'subject,realname'
+ + (Login[1] ? ',ID' : '')
+ + (Login[2] ? ',email' : '')
+ + (Login[3] ? ',password' : '')
+ + ',Score,Start_Time,End_Time'
+ ;
+ // add answer fields (except separators)
+ var r = new RegExp('^[^_]+_q\\d\\d_\\w+$');
+ for(var i=0; i<form.elements.length; i++) {
+ var n = form.elements[i].name;
+ if (r.test(n)) db_fields += ',' + n;
+ }
+ form.db_fields.value = db_fields;
+ }
+ // make sure delimiter is set (NS6+ requires this be set here, not any earlier)
+ form.db_delimiter.value = (DB[5] ? DB[5] : '\t');
+}
+function AddStudentDetailsToResultForm() {
+ var sDetails = '';
+ if (Login[0]) { // user name
+ // use 'realname' instead of a separate 'Name' field
+ // sDetails += hpHiddenField('Name', window.UserName);
+ }
+ if (Login[1]) { // user ID
+ sDetails += hpHiddenField('ID', window.UserID);
+ }
+ if (Login[2]) { // user email
+ sDetails += hpHiddenField('email', window.UserEmail);
+ }
+ if (sDetails && window.RegExp) {
+ // insert sDetails before '<input...Score...></input>'
+ var r = new RegExp('<input[^>]*Score[^>]*><\\/input>', 'i');
+ var m = r.exec(ResultForm);
+ if (m) {
+ ResultForm = ResultForm.replace(m[0], sDetails + m[0] + makeSeparator('Time_'));
+ sDetails = '';
+ }
+ }
+ if (Login[3]) { // quiz password
+ sDetails += hpHiddenField('Password', window.Password);
+ ResultForm = replaceLast('</form>', sDetails + '</form>', ResultForm);
+ }
+}
+function AddQuestionDetailsToResultForm() {
+ var qDetails = GetQuestionDetails();
+ if (qDetails) {
+ // insert qDetails before the final </form> tag in the ResultForm
+ ResultForm = replaceLast('</form>', qDetails + '</form>', ResultForm);
+ }
+}
+function AddDatabaseDetailsToResultForm() {
+ if (window.DB && DB[0] && !isGuest()) {
+ var dbDetails = '';
+ var folder = DB[1];
+ if (folder && folder.charAt(folder.length-1)!='/') folder += '/';
+ var file = DB[2];
+ if (file=='') {
+ file = location.href;
+ file= file.substring(file.lastIndexOf('/')+1);
+ var i = file.indexOf('?');
+ if (i >= 0) file = file.substring(0, i);
+ var i = file.lastIndexOf('.');
+ if (i >= 0) file = file.substring(0, i);
+ }
+ var ext = (DB[3] ? DB[3] : 'txt');
+ if (ext.charAt(0)!='.') ext = '.' + ext;
+ dbDetails += hpHiddenField('append_db', folder + file + ext);
+ dbDetails += hpHiddenField('db_fields', DB[4]);
+ dbDetails += hpHiddenField('db_delimiter', ''); // NS6+ requires this be set later
+ if (DB[6]) dbDetails += hpHiddenField('env_report', DB[6]);
+ // insert dbDetails before the final </form> tag in the ResultForm
+ ResultForm = replaceLast('</form>', dbDetails + '</form>', ResultForm);
+ }
+}
+function AddServerFieldsToResultForm() {
+ if (window.ServerFields) {
+ var s = ''; // input tags for s(erver fields)
+ for (var i=0; i<ServerFields.length; i++) {
+ if (ServerFields[i][0] && window.RegExp) {
+ // remove previous field value, if any
+ var r = new RegExp('<input[^>]*name\\s*=\\s*["\']\\s*' + ServerFields[i][0] + '[^>]*>(\\s*<\\/input>)?', 'i');
+ if (r.test(ResultForm)) {
+ ResultForm = ResultForm.replace(r, '');
+ }
+ }
+ if (ServerFields[i][1]) {
+ s += hpHiddenField(ServerFields[i][0], ServerFields[i][1]);
+ }
+ } // end for
+ if (s) ResultForm = replaceLast('</form>', s + '</form>', ResultForm);
+ }
+}
+function replaceLast(a, b, c) {
+ // replace last occurrence of 'a' in 'c' with 'b'
+ var l = a.length;
+ var i = c.lastIndexOf(a);
+ return (i<0 || l==0) ? c : (c.substring(0, i) + b + c.substring(i+l));
+}
+// *************************
+// Extract question details
+// *************************
+function GetQuestionDetails() {
+ var hp = hpVersion();
+ var t = hpQuizType();
+ var v = hpQuizVersion();
+ return (t==1) ? GetJbcQuestionDetails(hp, v) :
+ (t==2) ? GetJClozeQuestionDetails(hp, v) :
+ (t==3) ? GetJCrossQuestionDetails(hp, v) :
+ (t==4) ? GetJMatchQuestionDetails(hp, v) :
+ (t==5) ? GetJMixQuestionDetails(hp, v) :
+ (t==6) ? GetJQuizQuestionDetails(hp, v) :
+ (t==7) ? GetRhubarbDetails(hp, v) :
+ (t==8) ? GetSequiturDetails(hp, v) : '';
+}
+function GetJbcQuestionDetails(hp, v) {
+ qDetails = '';
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ // get question details
+ for(var q=0; q<I.length; q++) {
+ // initialize strings to hold answer details
+ var aDetails = new Array();
+ aDetails[0] = new Array(); // right
+ aDetails[1] = new Array(); // wrong
+ aDetails[2] = new Array(); // ignored
+ // get answer details
+ for(var a=0; a<I[q][1].length; a++) {
+ var i = (Status[q][1][a]=='R') ? 0 : (Status[q][1][a]=='0') ? 2 : 1;
+ aDetails[i][aDetails[i].length] = (JBC[6] ? a : I[q][1][a][0]);
+ }
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JBC', q);
+ // add separator, if required
+ if (JBC[0]) qDetails += makeSeparator(Q);
+ if (JBC[1]) { // number of attempts to answer question
+ qDetails += hpHiddenField(Q+'attempts', Status[q][2] + (Status[q][0]==1 ? 1 : 0));
+ }
+ if (JBC[2]) { // question text
+ qDetails += hpHiddenField(Q+'text', I[q][0]);
+ }
+ if (JBC[3] && (DB[0] || aDetails[0].length>0)) { // right
+ qDetails += hpHiddenField(Q+'right', aDetails[0]);
+ }
+ if (JBC[4] && (DB[0] || aDetails[1].length>0)) { // wrong
+ qDetails += hpHiddenField(Q+'wrong', aDetails[1]);
+ }
+ if (JBC[5] && (DB[0] || aDetails[2].length>0)) { // ignored
+ qDetails += hpHiddenField(Q+'ignored', aDetails[2]);
+ }
+ // calculate score for this question, if required (for HP version < 5.5)
+ if (isNaN(Status[q][3])) {
+ var a1 = Status[q][1].length; // answers
+ var a2 = Status[q][2]; // attempts
+ Status[q][3] = (a1<1 || a1<(a2-1)) ? 0 : ((a1 - (a2-1)) / a1);
+ }
+ // add 'score' for this question
+ qDetails += hpHiddenField(Q+'score', Math.floor(Status[q][3]*100)+'%');
+ } // end for
+ }
+ return qDetails;
+}
+function GetJClozeQuestionDetails(hp, v) {
+ var qDetails = '';
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ var r = hpRottmeier();
+ if (parseInt(r)==2) { // Rottmeier Find-It 3a+3b
+ qDetails += hpHiddenField('JCloze_penalties', window.TotWrongChoices);
+ }
+ // get details for each question
+ var q_max = (r==0) ? State.length : GapList.length; // could use I.length for both
+ for (var q=0; q<q_max; q++) {
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JCloze', q);
+ // add separator, if required
+ if (JCloze[0]) qDetails += makeSeparator(Q);
+ // score (as %)
+ var x = (hp==5) ? State[q][3] : (r==0) ? State[q].ItemScore : GapList[q][1].Score;
+ qDetails += hpHiddenField(Q+'score', Math.floor(x*100)+'%');
+ var correct = (HP[_correct][q] ? HP[_correct][q] : '');
+ if (JCloze[1]) { // student's correct answer
+ qDetails += hpHiddenField(Q+'correct', correct);
+ }
+ if (JCloze[2]) { // ignored answers
+ var x = new Array();
+ if (r!=2.1) { // exclude Find-It 3a
+ for (var i=0, ii=0; i<I[q][1].length; i++) {
+ var s = I[q][1][i][0];
+ if (typeof(s)=='string' && s!='' && (s.toUpperCase() != correct.toUpperCase())) {
+ x[ii++] = s;
+ }
+ }
+ }
+ qDetails += hpHiddenField(Q+'ignored', x);
+ }
+ if (JCloze[3]) {
+ var x = (HP[_wrong][q] ? HP[_wrong][q] : '');
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (JCloze[4]) { // number of penalties (Hints + Checks)
+ var x = (hp==5) ? State[q][1] : (r==0) ? State[q].HintsAndChecks : (r==1) ? GapList[q][1].NumOfTrials : (r==2.2) ? GapList[q][1].HintsAndChecks : 0;
+ qDetails += hpHiddenField(Q+'penalties', x);
+ }
+ if (JCloze[5]) { // clue shown?
+ var x = (hp==5) ? State[q][0] : (r==0) ? State[q].ClueGiven: (r==1) ? GapList[q][1].ClueAskedFor : false;
+ qDetails += hpHiddenField(Q+'clue_shown', (x ? 'YES' : 'NO'));
+ }
+ if (JCloze[6]) { // clue text
+ qDetails += hpHiddenField(Q+'clue_text', I[q][2]);
+ }
+ if (JCloze[7]) { // number of hints
+ var x = (HP[_hints][q] ? HP[_hints][q] : 0);
+ qDetails += hpHiddenField(Q+'hints', x);
+ }
+ if (JCloze[8]) { // number of clues
+ var x = HP[_clues][q] ? HP[_clues][q] : 0;
+ qDetails += hpHiddenField(Q+'clues', x);
+ }
+ if (JCloze[9]) { // number of checks (including the final one for the correct answer)
+ var x = (HP[_checks][q] ? HP[_checks][q] : 0);
+ qDetails += hpHiddenField(Q+'checks', x);
+ }
+ } // end for
+ }
+ return qDetails;
+}
+function GetJCrossQuestionDetails(hp, v) {
+ var qDetails = '';
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ // inialize letter count
+ var letters = 0;
+ // get details for each question
+ for (var row=0; row<L.length; row++) {
+ for (var col=0; col<L[row].length; col++) {
+ // increment letter count, if required
+ if (L[row][col]) letters++;
+ // show answers and clues, if required
+ var q = (hp==5) ? C[row][col] : CL[row][col];
+ if (q) {
+ for (var i=0; i<2; i++) { // 0==across, 1==down
+ var AD = (i==0) ? 'A' : 'D';
+ var acrossdown = (i==0) ? 'across' : 'down';
+
+ var clue = (hp==5) ? eval(AD+'['+q+']') : GetJCrossClue('Clue_'+AD+'_'+q);
+ if (clue) {
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JCross', q) + acrossdown + '_'; // e.g. JCross_01_across_
+
+ if (JCross[0]) {
+ qDetails += makeSeparator(Q);
+ }
+ if (JCross[5]) {
+ var x = (HP[_correct][AD] && HP[_correct][AD][q]) ? HP[_correct][AD][q] : '';
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (JCross[4]) qDetails += hpHiddenField(Q+'clue', clue);
+ if (JCross[5]) {
+ var x = (HP[_wrong][AD] && HP[_wrong][AD][q]) ? HP[_wrong][AD][q] : '';
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (JCross[6]) {
+ var x = HP[_clues][q] ? HP[_clues][q] : 0;
+ qDetails += hpHiddenField(Q+'clues', x);
+ }
+ if (JCross[7]) {
+ var x = (HP[_hints][AD] && HP[_hints][AD][q]) ? HP[_hints][AD][q] : 0;
+ qDetails += hpHiddenField(Q+'hints', x);
+ }
+ if (JCross[8]) {
+ var x = (HP[_checks][AD] && HP[_checks][AD][q]) ? HP[_checks][AD][q] : '';
+ qDetails += hpHiddenField(Q+'checks', x);
+ }
+ } // end for i
+ } // end if clue
+ } // end if q
+ } // end for col
+ } // end for row
+ if (JCross[2]) { // show number of letters
+ qDetails = hpHiddenField('JCross_letters', letters) + qDetails;
+ }
+ if (JCross[1]) { // show penalties
+ var x = (window.Penalties) ? Penalties : 0;
+ qDetails = hpHiddenField('JCross_penalties', x) + qDetails;
+ }
+ }
+ return qDetails;
+}
+function GetJCrossClue(id) {
+ var obj = (document.getElementById) ? document.getElementById(id) : null;
+ return (obj) ? GetTextFromNodeN(obj, 'Clue') : '';
+}
+function GetJCrossWord(a, r, c, goDown) {
+ // a is a 2-dimensional array of letters, r is a row number, c is a column number
+ var s = '';
+ while (r<a.length && c<a[r].length && a[r][c]) {
+ s += a[r][c];
+ if (goDown) {
+ r++;
+ } else {
+ c++;
+ }
+ }
+ return s;
+}
+function GetJMatchText(q, className) {
+ var obj = (document.getElementById) ? document.getElementById('Questions') : null;
+ return (obj) ? GetTextFromNodeN(obj, className, q) : '';
+}
+function GetJMatchRHS(v, q, getCorrect) {
+ var rhs = '';
+ if (v==5.1 || v==6.1) { // Drag-and-drop
+ var max_i = (window.F && window.D) ? D.length : 0;
+ for (var i=0; i<max_i; i++) {
+ if (F[q][1]==D[i][getCorrect ? 1 : 2]) break;
+ }
+ if (i<max_i) rhs = D[i][0];
+ } else if (v==5 || v==6) { // drop-down list of options
+ var obj=document.getElementById(Status[q][2]);
+ if (obj) { // not correct yet
+ if (getCorrect) {
+ var k = GetKeyFromSelect(obj);
+ var i_max = obj.options.length;
+ for (var i=0; i<i_max; i++) {
+ if (obj.options[i].value==k) break;
+ }
+ if (i>=i_max) i = 0; // shouldn't happen
+ } else {
+ // get current guess, if any
+ var i = obj.selectedIndex;
+ }
+ if (i) rhs = obj.options[i].innerHTML;
+ } else { // correct
+ rhs = GetJMatchText(q, 'RightItem');
+ }
+ }
+ return rhs;
+}
+function GetJMixQuestionDetails(hp, v) {
+ qDetails = '';
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ var q = 0; // question number
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JMix', q);
+ // add separator, if required
+ if (JMix[0]) qDetails += makeSeparator(Q);
+ // add 'score' for this question
+ var score = HP[_correct]==null ? 0 : ((Segments.length-Penalties)/Segments.length);
+ qDetails += hpHiddenField(Q+'score', Math.floor(score*100)+'%');
+ if (JMix[1]) { // number of wrong guesses
+ qDetails += hpHiddenField(Q+'wrongGuesses', Penalties);
+ }
+ if (JMix[2]) { // right answer
+ var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (JMix[3]) { // wrong answer(s)
+ var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (JMix[5]) { // checks
+ var x = (HP[_checks][q]) ? HP[_checks][q] : 0;
+ qDetails += hpHiddenField(Q+'checks', x);
+ }
+ if (JMix[6]) { // hints
+ var x = (HP[_hints][q]) ? HP[_hints][q] : 0;
+ qDetails += hpHiddenField(Q+'hints', x);
+ }
+ }
+ return qDetails;
+}
+function GetJMixSequence(indexes) {
+ var s = new Array();
+ for (var i=0; i<indexes.length; i++) {
+ s[i] = JMix[4] ? indexes[i] : GetJMixSegmentText(indexes[i]);
+ }
+ return s;
+}
+function GetJMixSegmentText(index){
+ var i_max = Segments.length;
+ for (var i=0; i<i_max; i++) {
+ if (Segments[i][1] == index) break;
+ }
+ return (i<i_max) ? Segments[i][0] : '';
+}
+function GetJQuizQuestionDetails(hp, v) {
+ var qDetails = '';
+ // HP5.5 uses "Status" for v5 and v6 JMatch quizzes (HP6 uses "State")
+ // var hp = (window.Status) ? 5 : (window.State) ? 6 : 0;
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ // get details for each question
+ var max_q = (hp==5) ? Status.length : State.length;
+ for (var q=0; q<max_q; q++) {
+ // skip this question if it was not used (HP6 v6 only)
+ if (hp==6 && !State[q]) continue;
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JQuiz', q);
+ // add separator
+ if (JQuiz[0]) qDetails += makeSeparator(Q);
+ if (hp==6 && JQuiz[11]) { // question type
+ var x = parseInt(I[q][2]);
+ x = (x==0) ? 'multiple-choice' : (x==1) ? 'short-answer' : (x==2) ? 'hybrid' : (x==3) ? 'multi-select' : 'n/a';
+ qDetails += hpHiddenField(Q+'type', x);
+ }
+ // score (as %)
+ var x = (hp==5) ? Status[q][4]*10 : I[q][0]*State[q][0];
+ if (x<0) x = 0;
+ qDetails += hpHiddenField(Q+'score', Math.floor(x)+'%');
+ if (hp==6 && JQuiz[10]) { // weighting
+ qDetails += hpHiddenField(Q+'weighting', I[q][0]);
+ }
+ if (JQuiz[1]) { // question text
+ var x = (hp==5) ? I[q][0] : (document.getElementById) ? GetTextFromNodeN(document.getElementById('Q_'+q), 'QuestionText') : '';
+ qDetails += hpHiddenField(Q+'question', x);
+ }
+ if (JQuiz[2]) { // student's correct answers
+ var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (JQuiz[3]) { // ignored and wrong answers
+ var x = (hp==5) ? new Array() : GetJQuizAnswerDetails(q, 1);
+ if (hp==5) {
+ for (var i=0; i<I[q][1].length; i++) {
+ var correct = HP[_correct][q] ? HP[_correct][q] : '';
+ if (I[q][1][i][0] && I[q][1][i][0].toUpperCase()!=correct.toUpperCase()) {
+ x[x.length] = I[q][1][i][0];
+ }
+ }
+ }
+ if (DB[0] || x) qDetails += hpHiddenField(Q+'other', x);
+ }
+ if (hp==6 && JQuiz[7]) { // all selected answers
+ var x = GetJQuizAnswerDetails(q, 0);
+ qDetails += hpHiddenField(Q+'selected', x);
+ }
+ if (JQuiz[8]) { // wrong answers
+ var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (hp==6 && JQuiz[9]) { // ignored answers
+ var x = GetJQuizAnswerDetails(q, 4);
+ qDetails += hpHiddenField(Q+'ignored', x);
+ }
+ if (JQuiz[4]) { // number of hints
+ var x = (HP[_hints][q]) ? HP[_hints][q] : 0;
+ qDetails += hpHiddenField(Q+'hints', x);
+ }
+ if (JQuiz[5] || JQuiz[12]) { // number of checks
+ if (JQuiz[12]) { // strictly checks only
+ var x = (HP[_checks][q]) ? HP[_checks][q] : 0;
+ } else { // checks (+ hints in HP6)
+ var x = (hp==5) ? Status[q][1] : (State[q][2]-1);
+ }
+ qDetails += hpHiddenField(Q+'checks', x);
+ }
+ if (JQuiz[13]) { // ShowAnswer button
+ var x = (HP[_clues][q]) ? HP[_clues][q] : 0;
+ qDetails += hpHiddenField(Q+'clues', x);
+ }
+ } // end for
+ } // end if
+ return qDetails;
+}
+function GetTextFromNodeN(obj, className, n) {
+ // returns the text under the nth node of obj with the target class name
+ var txt = '';
+ if (obj && className) {
+ if (typeof(n)=='undefined') {
+ n = 0;
+ }
+ var nodes = GetNodesByClassName(obj, className);
+ if (n<nodes.length) {
+ txt += GetTextFromNode(nodes[n]);
+ }
+ }
+ return txt;
+}
+function GetNodesByClassName(obj, className) {
+ // returns an array of nodes with the target classname
+ var nodes = new Array();
+ if (obj) {
+ if (className && obj.className==className) {
+ nodes.push(obj);
+ } else if (obj.childNodes) {
+ for (var i=0; i<obj.childNodes.length; i++) {
+ nodes = nodes.concat(GetNodesByClassName(obj.childNodes[i], className));
+ }
+ }
+ }
+ return nodes;
+}
+function GetTextFromNode(obj) {
+ // return text in (and under) a single DOM node
+ var txt = '';
+ if (obj) {
+ if (obj.nodeType==3) {
+ txt = obj.nodeValue + ' ';
+ }
+ if (obj.childNodes) {
+ for (var i=0; i<obj.childNodes.length; i++) {
+ txt += GetTextFromNode(obj.childNodes[i]);
+ }
+ }
+ }
+ return txt;
+}
+function GetJQuizAnswerDetails(q, flag) {
+ // flag : the type of information required about the student's answers
+ // 0 : all student's answers
+ // 1 : student's wrong and ignored answers
+ // 2 : student's correct answers
+ // 3 : student's wrong answers
+ // 4 : ignored answers
+ var x = State[q][5]; //Sequence of answers chosen by number
+ if (I[q][2]=='3') { // multi-select
+ if (flag==4) {
+ var x = new Array();
+ } else {
+ // get required part of 'x' and convert to array
+ var i = x.lastIndexOf('|');
+ var x = x.substring((flag==2 ? (i+1) : 1), ((flag==0 || flag==2) ? x.length : i)).split('|');
+ }
+ for (var i=0; i<x.length; i++) {
+ var a = new Array();
+ for (var ii=0; ii<x[i].length; ii++) {
+ if (x[i].charAt(ii)=='Y') {
+ var s = JQuiz[6] ? String.fromCharCode(97+ii) : I[q][3][ii][0];
+ if (s && s.replace && window.RegExp) {
+ s = s.replace(new RegExp('\\+', 'g'), '+');
+ }
+ a.push(s);
+ }
+ }
+ x[i] = a.join('+');
+ }
+ } else if (x) { // multiple-choice, short-answer and hybrid
+ // remove trailing comma and convert to array
+ x = x.substring(0, x.length-1).split(',');
+ if (flag) {
+ var a = new Array();
+ if (flag==1 || flag==2 || flag==3) {
+ for (var i=0; i<x.length; i++) {
+ var ii = I[q][3][(x[i].charCodeAt(0)-65)][2];
+ if(((flag==1 || flag==2) && ii==1) || (flag==3 && ii==0)) a.push(x[i]);
+ }
+ }
+ if (flag==1) {
+ x = a;
+ a = new Array();
+ }
+ if (flag==1 || flag==4) {
+ for (var i=0; i<I[q][3].length; i++) {
+ var s = String.fromCharCode(65+i);
+ for (var ii=0; ii<x.length; ii++) {
+ if (x[ii]==s) break;
+ }
+ if (ii==x.length) a.push(s);
+ }
+ }
+ x = a;
+ }
+ // convert answer indexes to values, if required
+ if (JQuiz[6]==false) {
+ for (var i=0; i<x.length; i++) {
+ var ii = x[i].charCodeAt(0) - 65;
+ x[i] = I[q][3][ii][0];
+ }
+ }
+ } else {
+ x = new Array();
+ }
+ return x;
+}
+function GetRhubarbDetails(v) {
+ qDetails = '';
+ if (v==6) {
+ var q = 0; // always zero
+ var Q = getQ('Rhubarb', q);
+ if (document.title) { // use quiz title as question name
+ qDetails += hpHiddenField(Q+'name', document.title);
+ }
+ if (Rhubarb[0]) { // correct words
+ var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+ if (Rhubarb[1]) { // count of correct words
+ for (var i=0,ii=0; i<x.length; i++) {
+ if (x[i]) ii++;
+ }
+ x = ii;
+ }
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (Rhubarb[2]) { // wrong words
+ var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+ if (Rhubarb[3]) { // count of wrong words
+ x = x.length;
+ }
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (Rhubarb[4]) { // ignored
+ var x = '';
+ qDetails += hpHiddenField(Q+'ignored', x);
+ }
+ if (Rhubarb[5]) { // hints
+ var x = (HP[_hints][q]) ? HP[_hints][q] : '';
+ qDetails += hpHiddenField(Q+'hints', x);
+ }
+ }
+ return qDetails;
+}
+function GetSequiturDetails(v) {
+ qDetails = '';
+ if (v==6) {
+ var q = 0; // always zero
+ var Q = getQ('Sequitur', q);
+ if (document.title) { // use quiz title as question name
+ qDetails += hpHiddenField(Q+'name', document.title);
+ }
+ if (Sequitur[0]) { // number of correct buttons chosen
+ var x = (HP[_correct][q]) ? HP[_correct][q] : '';
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (Sequitur[1]) { // number of wrong buttons chosen
+ var x = (HP[_wrong][q]) ? HP[_wrong][q] : '';
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ }
+ return qDetails;
+}
+// *********************
+// click event handlers
+// *********************
+function hpClick(x, args) {
+ // x is the button type
+ // args is either empty, a single argument, or an array of arguments
+ var btn = (x==1) ? 'Hint' : (x==2) ? 'Clue' : (x==3) ? 'Check' : (x==4) ? 'Enter' : '';
+ if (btn) {
+ // convert args to array, if necessary
+ var t = typeof(args);
+ if (t=='object') {
+ // do nothing (args is already an array)
+ } else if (t=='undefined') {
+ args = new Array();
+ } else {
+ args = new Array(''+args);
+ }
+ // call handler for this kind of button
+ var x = eval('hpClick'+btn+'('+hpVersion()+','+hpQuizType()+','+hpQuizVersion()+',args);');
+ }
+}
+function hpClickHint(hp, t, v, args) {
+ if (t==2 || t==5 || t==6 || t==7) { // JCloze, JMix, JQuiz, Rhubarb
+ var q = args[0]; // clue/question number
+ if (!HP[_hints][q]) HP[_hints][q] = 0;
+ HP[_hints][q]++;
+ }
+ if (t==3) { // JCross
+ if (v==6 || v==5) {
+ var q = args[0]; // clue/question number
+ var AD = args[1]; // direction ('A' or 'D')
+ if (!HP[_hints][AD]) HP[_hints][AD] = new Array();
+ if (!HP[_hints][AD][q]) HP[_hints][AD][q] = 0;
+ HP[_hints][AD][q]++;
+ }
+ }
+ return true;
+}
+function hpClickClue(hp, t, v, args) {
+ if (t==2 || t==3 || t==6) { // JCloze or JCross, or JQuiz (ShowAnswer button)
+ var q = args[0]; // clue/question number
+ if (!HP[_clues][q]) HP[_clues][q] = 0;
+ HP[_clues][q]++;
+ }
+ return true;
+}
+function hpClickCheck(hp, t, v, args) {
+ if (t==2) { // JCloze
+ if (v==5 || v==6) {
+ var r = hpRottmeier();
+ var already_correct = 'true';
+ if (r==0) {
+ already_correct = (hp==5) ? 'State[i][4]==1' : 'State[i].AnsweredCorrectly==true';
+ } else if (r==1) { // DropDown
+ already_correct = 'GapList[i][1].GapLocked==true';
+ } else if (r==2.1) { // Find-It 3a
+ already_correct = 'GapList[i][1].ErrorFound==true';
+ } else if (r==2.2) { // Find-It 3b
+ already_correct = 'GapList[i][1].GapSolved==true';
+ }
+ var i_max = I.length;
+ for (var i=0; i<i_max; i++) {
+ if (eval(already_correct)) continue;
+ var g = '';
+ if (r==0 || r==2.2) {
+ g = GetGapValue(i);
+ } else if (r==1) { // DropDown
+ if (hp==5) {
+ g = eval('document.Cloze.Gap'+i+'.value');
+ } else if (hp==6) {
+ g = Get_SelectedDropValue(i);
+ }
+ } else if (r==2.1 && i==args[0]) { // Find-It 3a
+ g = I[i][1][0][0];
+ }
+ if (g) {
+ if (!HP[_checks][i]) HP[_checks][i] = 0;
+ HP[_checks][i]++;
+ if (!HP[_guesses][i]) HP[_guesses][i] = new Array();
+ var ii = HP[_guesses][i].length;
+ // is this a new guess at this gap?
+ if (ii==0 || g!=HP[_guesses][i][ii-1]) {
+ HP[_guesses][i][ii] = g;
+ var G = g.toUpperCase();
+
+ var ii_max = I[i][1].length;
+ for (var ii=0; ii<ii_max; ii++) {
+ if (window.CaseSensitive) {
+ if (g==I[i][1][ii][0]) break;
+ } else {
+ if (G==I[i][1][ii][0].toUpperCase()) break;
+ }
+ }
+
+ if (ii==ii_max) { // guess is wrong
+ if (!HP[_wrong][i]) HP[_wrong][i] = new Array();
+ var ii_max = HP[_wrong][i].length;
+ for (var ii=0; ii<ii_max; ii++) {
+ if (HP[_wrong][i][ii]==g) break;
+ }
+ if (ii==ii_max) {
+ HP[_wrong][i][ii] = g;
+ }
+ } else { // guess is correct
+ HP[_correct][i] = g;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (t==3) { // JCross
+ if (v==5 || v==6) {
+ var q = args[0]; // clue/question number
+ for (var row=0; row<L.length; row++) {
+ for (var col=0; col<L[row].length; col++) {
+ var q = (v==5) ? C[row][col] : CL[row][col];
+ if (q) {
+ hpClickCheckJCrossV5V6(hp, v, 'A', q, row, col);
+ hpClickCheckJCrossV5V6(hp, v, 'D', q, row, col);
+ }
+ }
+ }
+ }
+ }
+ if (t==4) { // JMatch
+ var a = new Array();
+ var extra = ''; // extra js code to eval(uate)
+ var guess = ''; // js code to eval(uate) guess
+ var correct = ''; // js code to eval(uate) correct answer
+ if (window.D && window.F) {
+ // drag-and-drop, i.e. v5+ and v6+ (HP5 and HP6)
+ a = F;
+ guess = 'GetJMatchRHS(v,i)';
+ correct = 'GetJMatchRHS(v,i,true)';
+ } else if (window.GetKeyFromSelect) {
+ // HP6 v6
+ a = Status;
+ guess = 'GetJMatchRHS(v,i)';
+ correct = 'GetJMatchRHS(v,i,true)';
+ } else if (window.GetAnswer) {
+ // HP5 v6,v5
+ a = I;
+ guess = "(I[i][2]==0||I[i][0]=='')?'':GetAnswer(i)";
+ correct = 'I[i][3])';
+ } else if (window.Draggables) {
+ // HP5 v4
+ a = Draggables;
+ s = "Draggables[i].correct=='1'";
+ } else if (window.CorrectAnswers) {
+ // HP5 v3
+ a = CorrectAnswers;
+ guess = 'document.QuizForm.elements[i*2].selectedIndex';
+ correct = 'CorrectAnswers[i]';
+ }
+ for (var i=0; i<a.length; i++) {
+ // check this match has not already been finished
+ if (!HP[_correct][i]) {
+ // do extra setup, if necessary
+ if (extra) eval(extra);
+ // get the guess, if any
+ var g = ''+eval(guess);
+ if (g) {
+ // is the guess correct?
+ if (g==eval(correct)) {
+ HP[_correct][i] = g;
+ } else { // wrong answer
+ // initialize wrong guess array if necessary
+ if (!HP[_wrong][i]) HP[_wrong][i] = new Array();
+ // check to see if the guess is already in the guess array
+ var i_max = HP[_wrong][i].length;
+ for (var ii=0; ii<i_max; ii++) {
+ if (HP[_wrong][i][ii]==g) break;
+ }
+ // add the guess if it was not found
+ if (ii==i_max) {
+ HP[_wrong][i][ii]=g;
+ } else {
+ g = null; // this is not a new answer
+ }
+ }
+ // increment checks for this question, if necessary
+ if (g) {
+ if (!HP[_checks][i]) HP[_checks][i] = 0;
+ HP[_checks][i]++;
+ }
+ }
+ }
+ }
+ } // end if JMatch
+ if (t==5) { // JMix
+ // get question number (always 0)
+ var q = args[0];
+ // check question has not already been answered correctly
+ if (!HP[_correct][q]) {
+ // match current guess against possible correct answers
+ var a_max = Answers.length;
+ for (var a=0; a<a_max; a++) {
+ var i_max = Answers[a].length;
+ for (var i=0; i<i_max; i++) {
+ if (Answers[a][i] != GuessSequence[i]) break;
+ }
+ if (i==i_max) break; // correct answer was found
+ }
+ // at this point, (a==a_max) means guess is wrong
+ // get array of segment texts in this g(uess)
+ var g = GetJMixSequence(GuessSequence);
+ // convert g(uess) array and to a s(tring)
+ var s = '';
+ var i_max = g.length;
+ for (var i=0; i<i_max; i++) {
+ g[i] = trim(g[i]);
+ if (g[i]!='') {
+ s += (s=='' ? '' : '+') + g[i];
+ }
+ }
+ if (s) {
+ if (a==a_max) { // wrong
+ if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+ var i = HP[_wrong][q].length;
+ HP[_wrong][q][i] = s;
+ } else { // correct
+ HP[_correct][q] = s;
+ }
+ // increment checks for this question
+ if (!HP[_checks][q]) HP[_checks][q] = 0;
+ HP[_checks][q]++;
+ }
+ }
+ }
+ if (t==6) { // JQuiz
+ if (hp==5 || hp==6) {
+ var q = args[0]; // clue/question number
+ if (hp==5) {
+ if (v==5) {
+ var g = TrimString(eval('BottomFrame.document.QForm' + q + '.Guess').value);
+ } else if (v==6) {
+ var g = TrimString(eval('document.QForm.Guess').value);
+ }
+ } else { // HP 6
+ var g = args[1];
+ }
+ // increment check count
+ if (!HP[_checks][q]) HP[_checks][q] = 0;
+ HP[_checks][q]++;
+ if (g) {
+ var G = g.toUpperCase(); // used for shortanswer only
+ var correct_answer = ''; // used for multiselect only
+ // set index of answer array in I (the question array)
+ var ans = (hp==5) ? 1 : 3;
+ var i_max = I[q][ans].length;
+ for (var i=0; i<i_max; i++) {
+ // is this a (possible) correct answer?
+ if (hp==5 || (hp==6 && I[q][ans][i][2])) {
+ if (hp==6 && I[q][2]==3) { // multiselect
+ correct_answer += (correct_answer ? '+' : '') + I[q][ans][i][0];
+ } else { // multichoice, shortanswer
+ if (window.CaseSensitive) {
+ if (g==I[q][ans][i][0]) break;
+ } else {
+ if (G==I[q][ans][i][0].toUpperCase()) break;
+ }
+ }
+ }
+ }
+ if (i==i_max && g!=correct_answer) { // wrong
+ if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+ var i_max = HP[_wrong][q].length;
+ for (var i=0; i<i_max; i++) {
+ if (HP[_wrong][q][i]==g) break;
+ }
+ if (i==i_max) HP[_wrong][q][i] = g;
+ } else {
+ HP[_correct][q] = g;
+ }
+ }
+ }
+ }
+ if (t==7) { // Rhubarb
+ if (hp==6) {
+ var q = 0; // question number (always zero)
+ var g = args[0]; // InputWord from CheckGuess()
+ if (g) {
+ var G = g.toUpperCase();
+ var i_max = Words.length;
+ for (var i=0; i<i_max; i++) {
+ if (G==Words[i].toUpperCase()) break;
+ }
+ if (i<i_max) { // correct
+ if (!HP[_correct][q]) HP[_correct][q] = new Array();
+ HP[_correct][q][i] = g;
+ } else { // wrong
+ if (!HP[_wrong][q]) HP[_wrong][q] = new Array();
+ var i_max = HP[_wrong][q].length;
+ for (var i=0; i<i_max; i++) {
+ if (G==HP[_wrong][q][i].toUpperCase()) break;
+ }
+ if (i==i_max) HP[_wrong][q][i] = g;
+ }
+ }
+ }
+ }
+ if (t==8) { // Sequitur
+ if (hp==6) {
+ var q = 0; // question number (always zero)
+ if (CurrentCorrect==args[0]) { // correct button chosen
+ if (!HP[_correct][q]) HP[_correct][q] = 0;
+ HP[_correct][q]++;
+ } else {
+ if (!HP[_wrong][q]) HP[_wrong][q] = 0;
+ HP[_wrong][q]++;
+ }
+ }
+ }
+ return true;
+}
+function hpClickCheckJCrossV5V6(hp, v, AD, q, row, col) {
+ // v is the version of Hot Potatoes
+ // AD is the direction ('A' or 'D')
+ // make sure HP[_checks] and HP[_correct] are initialized
+ if (!HP[_checks][AD]) HP[_checks][AD] = new Array();
+ if (!HP[_correct][AD]) HP[_correct][AD] = new Array();
+ // get clue, if any
+ var clue = (hp==5) ? eval('window.'+AD) : GetJCrossClue('Clue_'+AD+'_' + q);
+ // is this a question that has not been answered correctly yet?
+ if (clue && !HP[_correct][AD][q]) {
+ var check = false;
+ var guess = GetJCrossWord(G, row, col, (AD=='D'));
+ var correct = GetJCrossWord(L, row, col, (AD=='D'));
+ if (guess==correct) {
+ HP[_correct][AD][q] = correct;
+ check = true;
+ } else if (guess) {
+ // make sure HP[_wrong] is initialized
+ if (!HP[_wrong][AD]) HP[_wrong][AD] = new Array();
+ if (!HP[_wrong][AD][q]) HP[_wrong][AD][q] = new Array();
+ // check this guess has not been entered before
+ var i_max = HP[_wrong][AD][q].length;
+ for (var i=0; i<i_max; i++) {
+ if (HP[_wrong][AD][q]==guess) break;
+ }
+ // add the guess if it has not been entered before
+ if (i>=i_max) {
+ HP[_wrong][AD][q][i] = guess;
+ check = true;
+ }
+ }
+ // update HP[_checks], if necessary
+ if (check) {
+ if (!HP[_checks][AD]) HP[_checks][AD] = new Array();
+ if (!HP[_checks][AD][q]) HP[_checks][AD][q] = 0;
+ HP[_checks][AD][q]++;
+ }
+ }
+}
+function hpClickEnter(hp, t, v, args) {
+ if (t==3) { // JCross
+ var q = args[0]; // clue/question number
+ if (!HP[_enter][q]) HP[_enter][q] = 0;
+ HP[_enter][q]++;
+ }
+ return true;
+}
+function GetJMatchQuestionDetails(hp, v) {
+ var qDetails = '';
+ // HP5.5 uses "I" for v5 and v6 JMatch quizzes
+ // var hp5 = (window.I) ? true : false;
+ // check the quiz version
+ if (hp==5 || hp==6) {
+ if (JMatch[1] && v==6.1) { // attempts
+ qDetails += hpHiddenField('JMatch_attempts', Penalties+1);
+ }
+ // get number of questions
+ var max_q = (hp==5 || v==6) ? Status.length : F.length;
+ // get details for each question
+ for (var q=0; q<max_q; q++) {
+ // format 'Q' (a padded, two-digit version of 'q')
+ var Q = getQ('JMatch', q);
+ // add separator, if required
+ if (JMatch[0] && (JMatch[1] || JMatch[2] || JMatch[3])) {
+ qDetails += makeSeparator(Q);
+ }
+ if (JMatch[1] && (hp==5 || v==6)) { // attempts
+ qDetails += hpHiddenField(Q+'attempts', Status[q][1]);
+ }
+ if (JMatch[2]) { // LHS text (the question)
+ var x = (v==5) ? I[q][0] : (v==6) ? GetJMatchText(q, 'LeftItem') : F[q][0];
+ qDetails += hpHiddenField(Q+'lhs', x);
+ }
+ if (JMatch[3]) { // correct answer (if any)
+ var x = HP[_correct][q] ? HP[_correct][q] : '';
+ qDetails += hpHiddenField(Q+'correct', x);
+ }
+ if (JMatch[4]) { // wrong answers (if any)
+ var x = HP[_wrong][q] ? HP[_wrong][q] : '';
+ qDetails += hpHiddenField(Q+'wrong', x);
+ }
+ if (JMatch[5]) { // checks
+ var x = HP[_checks][q] ? HP[_checks][q] : 0;
+ qDetails += hpHiddenField(Q+'checks', x);
+ }
+ } // end for
+ }
+ return qDetails;
+}
+// *********************
+// library functions
+// *********************
+function pad(i, l) {
+ var s = (i+'');
+ while (s.length<l) s = '0' + s;
+ return s;
+}
+function getQ(section, q) {
+ // Q is a padded, two-digit version of the question number, 'q', prefixed by 'section'
+ return section + '_q' + (q<9 ? '0' : '') + (q+1) + '_';
+}
+function makeSeparator(Q) {
+ return is_LMS() ? '' : hpHiddenField(Q.substring(0, Q.length-1), '---------------------------------');
+}
+function hpHiddenField(name, value, comma, forceHTML) {
+ var field = '';
+ var t = typeof(value);
+ if (t=='string') {
+ value = encode_entities(value);
+ } else if (t=='object') { // array
+ var values = value;
+ var i_max = values.length;
+ value = '';
+ if (comma==null) comma = ',';
+ for (var i=0; i<i_max; i++) {
+ values[i] = trim(values[i]);
+ if (values[i]!='') {
+ value += (i==0 ? '' : comma) + encode_entities(values[i]);
+ }
+ }
+ }
+ if (is_LMS() && !forceHTML) {
+ if (value && value.indexOf && value.indexOf('<')>=0 && value.indexOf('>')>=0) {
+ value = '<![CDATA[' + value + ']]>';
+ }
+ field = '<field><fieldname>' + name + '</fieldname><fielddata>' + value + '</fielddata></field>';
+ } else {
+ field = '<input type=hidden name="' + name + '" value="' + value + '">';
+ }
+ return field;
+}
+function trim(s) {
+ if (s==null) s = '';
+ var i = 0;
+ var ii = s.length;
+ while (i<ii && s.charAt(i)==' ') {
+ i++;
+ }
+ while (ii>i && s.charAt(ii-1)==' ') {
+ ii--;
+ }
+ return s.substring(i, ii);
+}
+function encode_entities(s_in) {
+ var i_max = (s_in) ? s_in.length : 0;
+ var s_out = '';
+ for (var i=0; i<i_max; i++) {
+ var c = s_in.charCodeAt(i);
+ // 34 : double quote .......["] &
+ // 38 : single quote .......['] '
+ // 43 : plus sign ..........[+]
+ // 44 : comma ..............[,]
+ // 60 : left angle bracket .[<] <
+ // 62 : right angle bracket [>] >
+ // >=128 multibyte character
+ s_out += (c==43 || c==44 || c>=128) ? ('&#x' + pad(c.toString(16), 4) + ';') : s_in.charAt(i);
+ }
+ return s_out;
+}
+// *********************
+// initialization
+// functions
+// *********************
+function getTime(obj) {
+ obj = obj ? obj : new Date();
+ // get year, month and day
+ // for an LMS : yyyy-mm-dd
+ // for email : DayName MonthName dd yyyy
+ var s = is_LMS() ?
+ obj.getFullYear() + '-' + pad(obj.getMonth()+1, 2) + '-' + pad(obj.getDate(), 2) :
+ MSG[16][obj.getDay()] + ' ' + MSG[17][obj.getMonth()] + ' ' + pad(obj.getDate(), 2) + ' ' + obj.getFullYear()
+ ;
+ // get hours, minutes and seconds (hh:mm:ss)
+ s += ' ' + pad(obj.getHours(), 2) + ':' + pad(obj.getMinutes(), 2) + ':' + pad(obj.getSeconds(), 2);
+ // get time difference
+ // for an LMS : +xxxx
+ // for email : GMT+xxxx
+ var x = obj.getTimezoneOffset(); // e.g. -540
+ if (!isNaN(x)) {
+ s += ' ' + (is_LMS() ? '' : 'GMT') + (x<0 ? '+' : '-');
+ x = Math.abs(x);
+ s += pad(parseInt(x/60), 2) + pad(x - (parseInt(x/60)*60), 2);
+ }
+ return s;
+}
+function getFunc(fn) {
+ if (typeof(fn)=='string') {
+ fn = eval('window.' + fn);
+ }
+ return (typeof(fn)=='function') ? fn : null;
+}
+function getFuncCode(fn, extraCode, anchorCode, beforeAnchor) {
+ var s = '';
+ var obj = getFunc(fn);
+ if (obj) {
+ s = obj.toString();
+ var i1 = s.indexOf('{')+1;
+ var i2 = s.lastIndexOf('}');
+ if (i1>0 && i1<i2) {
+ s = s.substring(i1, i2);
+ }
+ }
+ if (extraCode) {
+ if (anchorCode) {
+ if (beforeAnchor) {
+ s = replaceLast(anchorCode, extraCode + anchorCode, s);
+ } else {
+ s = replaceLast(anchorCode, anchorCode + extraCode, s);
+ }
+ } else {
+ if (beforeAnchor) {
+ s = extraCode + s;
+ } else {
+ s = s + extraCode;
+ }
+ }
+ }
+ return s;
+}
+function getArgsStr(args) {
+ // make s(tring) version of function args array
+ var s = '';
+ var i_max = args.length;
+ for (var i=0; i<i_max; i++) {
+ s += '"' + args[i] + '",';
+ }
+ return s;
+}
+function getFuncArgs(fn, flag) {
+ // flag==0 : return args as string
+ // flag==1 ; return args as array
+ var i = 0;
+ var a = new Array();
+ var obj = getFunc(fn);
+ if (obj) {
+ var s = obj.toString();
+ var i1 = s.indexOf('(') + 1;
+ var i2 = s.indexOf(')', i1);
+ // add args to a(rray)
+ while (i1>0 && i1<i2) {
+ var i3 = s.indexOf(',', i1); // next comma
+ if (i3<0 || i3>i2) i3 = i2;
+ a[i++] = trim(s.substring(i1, i3));
+ i1 = i3+1;
+ }
+ }
+ return flag ? a : getArgsStr(a);
+}
+function getPrompt(fn) {
+ // the LoginPrompt is the text string in the first prompt(...) statement
+ // v5 : in the StartUp function
+ // v6 : in the GetUserName function
+ // Note: netscape uses double-quote as delimiter, others use single quote
+ var s = getFuncCode(fn);
+ var i1 = s.indexOf('prompt') + 8;
+ var i2 = s.indexOf(s.charAt(i1-1), i1);
+ var p = (i1>=8 && i2>i1) ? s.substring(i1, i2) : '';
+ // make sure browser has decoded the unicode prompt properly
+ // this check is mainly for ns4, but there may be others
+ if (window.RegExp) {
+ var r = new RegExp('u([0-9A-F]{4})');
+ var m = r.exec(p);
+ while (m) {
+ p = p.replace(m[0], '&#' + parseInt(m[1], 16) + ';');
+ m = r.exec(p);
+ }
+ }
+ return p;
+}
+function getStartUpCode(fn) {
+ // the main initialization code comes from the StartUp function
+ // v5 : the code before "UserName", if any,
+ // and the code after the 2nd subsequent '}'
+ // v6 : the code before and after 'GetUserName();'
+ // i.e. all the code except the call to 'GetUserName();'
+ var s = getFuncCode(fn);
+ var i1 = s.indexOf('GetUserName();');
+ if (i1>=0) { // v6
+ var i2 = i1 + 14;
+ } else { // v5
+ var i1 = s.indexOf('UserName');
+ var i2 = s.indexOf('}', s.indexOf('}', i1+8)+1)+1;
+ }
+ return (0<i1 && i1<i2) ? s.substring(0, i1) + s.substring(i2) : '';
+}
+function is_LMS() {
+ if (!window.hpCheckedForm) {
+ window.hpCheckedForm = true;
+ window.hpFoundForm = hpFindForm('store') ? true : false;
+ }
+ return hpFoundForm;
+}
+function hpFeedback() {
+ if (FEEDBACK[0]) {
+ var url = '';
+ var html = '';
+ if (FEEDBACK[1] && FEEDBACK[2]) { // formmail
+ html += '<html><body>'
+ + '<form action="' + FEEDBACK[0] + '" method="POST">'
+ + '<table border="0">'
+ + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'
+ + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'
+ ;
+ if (typeof(FEEDBACK[1])=='string') {
+ html += FEEDBACK[1] + hpHiddenField('recipient', FEEDBACK[1], ',', true);
+ } else if (typeof(FEEDBACK[1])=='object') {
+ var i_max = FEEDBACK[1].length;
+ if (i_max==1) { // one teacher
+ html += FEEDBACK[1][0][0] + hpHiddenField('recipient', FEEDBACK[1][0][0]+' <'+FEEDBACK[1][0][1]+'>', ',', true);
+ } else if (i_max>1) { // several teachers
+ html += '<select name="recipient">';
+ for (var i=0; i<i_max; i++) {
+ html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';
+ }
+ html += '</select>';
+ }
+ }
+ html += '</td></tr>'
+ + '<tr><th valign="top" align="right">' + FEEDBACK[9] + ':</th>'
+ + '<td><TEXTAREA name="message" rows="10" cols="40"></TEXTAREA></td></tr>'
+ + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">'
+ + hpHiddenField('realname', FEEDBACK[2], ',', true)
+ + hpHiddenField('email', FEEDBACK[3], ',', true)
+ + hpHiddenField('subject', document.title, ',', true)
+ + hpHiddenField('title', document.title, ',', true)
+ + hpHiddenField('return_link_title', FEEDBACK[10], ',', true)
+ + hpHiddenField('return_link_url', 'javascript:self.close()', ',', true)
+ + '</td></tr></table></form></body></html>'
+ ;
+ } else if (FEEDBACK[1]) { // url only
+ if (typeof(FEEDBACK[1])=='object') {
+ var i_max = FEEDBACK[1].length;
+ if (i_max>1) { // several teachers
+ html += '<html><body>'
+ + '<form action="' + FEEDBACK[0] + '" method="POST" onsubmit="this.action+=this.recipient.options[this.recipient.selectedIndex].value">'
+ + '<table border="0">'
+ + '<tr><th valign="top" align="right">' + FEEDBACK[7] + ':</th><td>' + document.title + '</td></tr>'
+ + '<tr><th valign="top" align="right">' + FEEDBACK[8] + ': </th><td>'
+ ;
+ html += '<select name="recipient">';
+ for (var i=0; i<i_max; i++) {
+ html += '<option value="'+FEEDBACK[1][i][1]+'">' + FEEDBACK[1][i][0] + '</option>';
+ }
+ html += '</select>';
+ html += '</td></tr>'
+ + '<tr><td> </td><td><input type="submit" value="' + FEEDBACK[6] + '">'
+ + '</td></tr></table></form></body></html>'
+ ;
+ } else if (i_max==1) { // one teacher
+ url = FEEDBACK[0] + FEEDBACK[1][0][1];
+ }
+ } else if (typeof(FEEDBACK[1])=='string') {
+ url = FEEDBACK[0] + FEEDBACK[1];
+ }
+ } else {
+ url = FEEDBACK[0];
+ }
+ if (url || html) {
+ var w = openWindow(url, 'feedback', FEEDBACK[4], FEEDBACK[5], 'RESIZABLE,SCROLLBARS', html);
+ if (!w) {
+ // unable to open popup window
+ alert(MSG[18]);
+ }
+ }
+ }
+}
+// ********************
+// intercept clicks
+// ********************
+function hpInterceptFeedback() {
+ // modify the function which writes feedback
+ // v6: ShowMessage(Feedback)
+ // but Rhubarb prints score in other functions, so use 'CheckFinished'
+ // v5: WriteFeedback(Feedback)
+ // v4: WriteFeedback(Stuff)
+ // v3: WriteFeedback(Feedback) [except JMatch]
+ // v3: CheckAnswer() [JMatch only]
+ var f = '';
+ if (window.CheckWord) { // Rhubarb
+ f = 'CheckFinished';
+ window.FEEDBACK = null;
+ } else if (window.ShowText) { // Sequitur
+ f = 'CheckAnswer';
+ window.FEEDBACK = null;
+ } else { // JBC, JCloze, JCross, JMatch, JMix, JQuiz
+ f = window.ShowMessage ? 'ShowMessage' : window.WriteFeedback ? 'WriteFeedback' : 'CheckAnswer';
+ }
+ if (f) {
+ var s = getFuncCode(f) + 'Finish();';
+ var a = getFuncArgs(f, true);
+ if (a[0] && window.FEEDBACK && FEEDBACK[0]) {
+ s = a[0] + "+='<br /><br />" + '<a href="javascript:hpFeedback();">' + FEEDBACK[6] + "</A>';" + s;
+ }
+ eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+ }
+}
+function hpInterceptHints() {
+ // modify the function which shows hints
+ // JBC: none
+ // JCloze v3-v6: ShowHint()
+ // JCross v3: Cheat(), v4: ShowHint(), v5-v6[HP5]: ShowHint(Across,x,y,BoxName), v6[HP6]: ShowHint(Across,ClueNum,x,y,BoxId)
+ // JMatch: none
+ // JMix v5-v6: CheckAnswer(CheckType=1)
+ // JQuiz v3: CheckAnswer(ShowHint=true, QNum), v4: CheckAnswer(ShowHint=true), v5-v6[HP5]: CheckAnswer(ShowHint=true,QNum), v6[HP6]: ShowHint(QNum)
+ var x = ''; // extra code, if any
+ if (window.Cheat) {
+ // JCross v3 ?
+ } else if (window.ShowHint) {
+ var f = 'ShowHint';
+ var a = getFuncArgs(f, true);
+ if (a.length==0) {
+ if (window.FindCurrent) {
+ // JCloze v3-v6
+ x = 'var q=window.Locked?-1:FindCurrent();if(q>=0&&GetHint(q))hpClick(1,q);';
+ } else {
+ // JCross v4
+ // work out which box would have a hint added
+ // work out which question that box is part of using GridMap and WinLetters
+ }
+ } else if (a[0]=='Across') {
+ if (a[1]=='ClueNum') {
+ // JCross v6 [HP6]
+ x = "var args=new Array(ClueNum,Across?'A':'D');hpClick(1,args);";
+ } else if (a[1]=='x' && a[2]=='y') {
+ // JCross v5-v6 [HP5]
+ x = "var args=new Array(C[x][y],Across?'A':'D');hpClick(1,args);";
+ }
+ } else if (a[0]=='QNum') {
+ // JQuiz v6[HP6]
+ x = 'hpClick(1,QNum);';
+ }
+ } else if (window.Hint) {
+ // Rhubarb
+ var f = 'Hint';
+ var a = getFuncArgs(f, true);
+ x = 'hpClick(1,0);'; // question number is always zero
+
+ } else if (window.CheckAnswer) {
+ var f = 'CheckAnswer';
+ var a = getFuncArgs(f, true);
+ if (a[0]=='ShowHint') {
+ if (a[1]=='QNum') {
+ // JQuiz v3, v5-v6[HP5]
+ x = 'if(ShowHint)hpClick(1,QNum);';
+ } else {
+ // JQuiz v4
+ x = 'if(ShowHint)hpClick(1,QNum-1);'; // QNum is a global variable
+ }
+ } else if (a[0]=='CheckType') {
+ // JMix v5-v6
+ x = 'if(CheckType==1)hpClick(1,0);'; // question number is always 0;
+ }
+ }
+ // add the e(x)tra code, if any, to the start of the hint (f)unction
+ if (x) {
+ var s = getFuncCode(f, x, '', true);
+ eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+ }
+}
+function hpInterceptClues() {
+ // modify the function which shows clues (or ShowAnswers in JQuiz)
+ // JBC: none
+ // JCloze v3-v6: ShowClue(ItemNum)
+ // JCross v3-v4: ShowClue(ClueNum), v5-v6: ShowClue(ClueNum,x,y)
+ // JMatch none
+ // JMix none
+ // JQuiz ShowAnswers(QNum)
+ var x = ''; // extra code, if any
+ if (window.ShowClue) {
+ var f = 'ShowClue';
+ var a = getFuncArgs(f, true);
+ if (a[0]=='ItemNum') {
+ // JCloze (v3-v6)
+ x = 'if(!window.Locked)hpClick(2,ItemNum);'; // v6 [HP6] uses window.Locked
+ } else if (a[0]=='ClueNum') {
+ if (a[1]=='x' && a[2]=='y') {
+ if (window.A && window.D) {
+ // JCross v5-v6 [HP5]
+ x = 'if(A[ClueNum]||D[ClueNum])hpClick(2,ClueNum);';
+ } else if (document.getElementById) {
+ // JCross v6 [HP6]
+ x = "if(document.getElementById('clue_' + ClueNum)||document.getElementById('Clue_D_' + ClueNum))hpClick(2,ClueNum);";
+ }
+ } else {
+ if (window.AClues && window.DClues) {
+ // JCross v3-v4
+ x = 'if(AClues[ClueNum]||DClues[ClueNum])hpClick(2,ClueNum);';
+ }
+ }
+ }
+ }
+ // JQuiz: there is no "ShowClue" function but there is a "ShowAnswer" function
+ if (window.ShowAnswers) {
+ var f = 'ShowAnswers';
+ var a = getFuncArgs(f, true);
+ if (window.State) {
+ if (window.ShowMessage) {
+ // JQuiz v6 [HP6]
+ x = 'if(State[QNum][0]<1)hpClick(2,QNum);';
+ } else if (window.WriteFeedback) {
+ // JQuiz v3-v4
+ x = 'if(State[QNum-1][0]<1)hpClick(2,QNum-1);';
+ }
+ } else if (window.Status) {
+ // JQuiz v5-v6 [HP5]
+ x = 'if(Status[QNum][0]<0)hpClick(5,QNum);';
+ }
+ }
+ // add the e(x)tra code, if any, to the start of the clue (f)unction
+ if (x) {
+ var s = getFuncCode(f, x, '', true);
+ eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+ }
+}
+function hpInterceptChecks() {
+ // modify the function which handles checks
+ // JBC: none
+ // JCloze CheckAnswers()
+ // NB: Rottmeier Find-It 3a: CheckText(GapState,GapId)
+ // JCross none
+ // JMatch HP5 v3, v5, v6: CheckAnswer(), HP5 v4: CheckResults(), HP6: CheckAnswers()
+ // JMix CheckAnswer(CheckType)
+ // JQuiz
+ // HP5: CheckAnswer(ShowHint, QNum)
+ // HP6: CheckMCAnswer, CheckMultiSelAnswer, CheckShortAnswer
+ // Rhubarb CheckWord(InputWord)
+ // Sequitur CheckAnswer(Chosen, Btn)
+ // HP6 JQuiz has three "Check Answer" functions
+ var f = new Array('CheckMCAnswer', 'CheckMultiSelAnswer', 'CheckShortAnswer');
+ for (var i=0; i<f.length; i++) {
+ if (eval('window.' + f[i])) {
+ var a = getFuncArgs(f[i], true);
+ var x = "";
+ if (f[i]=='CheckMCAnswer') {
+ x += "var args=new Array(QNum,I[QNum][3][ANum][0]);";
+ } else if (f[i]=='CheckShortAnswer') {
+ x += ""
+ + "var obj=document.getElementById('Q_'+QNum+'_Guess');"
+ + "var args=new Array(QNum,obj.value);"
+ ;
+ } else if (f[i]=='CheckMultiSelAnswer') {
+ x += ""
+ + "var g='';"
+ + "for (var ANum=0; ANum<I[QNum][3].length; ANum++){"
+ + "var obj=document.getElementById('Q_'+QNum+'_'+ANum+'_Chk');"
+ + "if (obj.checked)g+=(g?'+':'')+I[QNum][3][ANum][0];"
+ + "}"
+ + "var args=new Array(QNum,g);"
+ ;
+ }
+ if (x) {
+ x = "if(!Finished&&State[QNum].length&&State[QNum][0]<0){" + x + "hpClick(3,args)}";
+ var s = getFuncCode(f[i], x, '', true);
+ eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');
+ }
+ }
+ }
+ var f = ''; // function name
+ var x = ''; // extra code, if any
+ if (window.CheckAnswer) {
+ f = 'CheckAnswer';
+ var a = getFuncArgs(f, true);
+ if (a[0]=='ShowHint') {
+ if (a[1]=='QNum') {
+ // JQuiz v3, v5-v6[HP5]
+ x = 'if(!ShowHint&&Status[QNum][0]<1)hpClick(3,QNum);';
+ } else {
+ // JQuiz v4
+ x = 'if(!ShowHint&&State[QNum-1][0]<1)hpClick(3,QNum-1);'; // QNum is a global variable
+ }
+ } else if (a[0]=='CheckType') {
+ // JMix v5-v6
+ x = 'if(CheckType==0)hpClick(3,0);'; // question number is always 0;
+ } else if (a[0]=='Chosen') {
+ // Sequitur
+ x = 'if (!(CurrentNumber==TotalSegments||AllDone||Btn.innerHTML==IncorrectIndicator))hpClick(3,Chosen);';
+ }
+ } else if (window.CheckWord) {
+ f = 'CheckWord';
+ var a = getFuncArgs(f, true);
+ if (a[0]=='InputWord') {
+ // Rhubarb
+ x = 'if(!window.AllDone)hpClick(3,InputWord);';
+ }
+ } else if (window.CheckText && !window.CheckAnswers) { // Rottmeier Find-It (3a)
+ f = 'CheckText';
+ var a = getFuncArgs(f, true);
+ if ((a[0]=='bool' && a[1]=='item') || (a[0]=='GapState' && a[1]=='GapId')) {
+ x = 'if(!window.Finished&&'+a[0]+')hpClick(3,'+a[1]+');';
+ }
+ }
+ if (f) {
+ var s = getFuncCode(f, x, '', true);
+ eval('window.' + f + '=new Function(' + getArgsStr(a) + 's);');
+ }
+ // JMatch has three possible check functions, depending on the version
+ // (NB: other quiz types also have these functions)
+ var f = new Array('CheckAnswers', 'CheckAnswer', 'CheckResults');
+ for (var i=0; i<f.length; i++) {
+ if (eval('window.' + f[i])) {
+ var a = getFuncArgs(f[i], true);
+ if (a.length==0) {
+ var s = getFuncCode(f[i], "hpClick(3);", '', true);
+ eval('window.' + f[i] + '=new Function(' + getArgsStr(a) + 's);');
+ break; // out of the loop
+ }
+ }
+ }
+}
+// ***************
+// fix IE5 and NS6
+// ***************
+// add Array.push if required (allows v6 quizzes to run on ie5win)
+if (Array.prototype && Array.prototype.push==null) {
+ Array.prototype.push = new Function("x", "this[this.length]=x");
+}
+// add attachEvent function, if required (allows HP5 v6 quizzes to run on ie5mac)
+// NOTE: to allow v6 quizzes on ie5mac, the following code
+// needs to be inserted BEFORE the Hot Potatoes javascript
+if (window.attachEvent==null) {
+ window.attachEvent = new Function('evt', 'fn', 'eval("window."+evt+"="+fn)');
+}
+if (document.attachEvent==null) {
+ document.attachEvent = new Function('evt', 'fn', 'eval("document."+evt+"="+fn)');
+}
+// fix the ShowMessage function for NS6
+// by removing calls to a button's "focus()" method
+if (navigator.userAgent.indexOf("Netscape6")>=0 && window.ShowMessage) {
+ var s = ShowMessage.toString();
+ var r = new RegExp('document\\.getElementById\\((\'|")FeedbackOKButton(\'|")\\)\\.focus\\(\\);', 'gi');
+ s = s.substring(s.indexOf('{')+1, s.lastIndexOf('}')).replace(r, '');
+ window.ShowMessage = new Function('Feedback', s);
+}
+// ns6.0 (in JMix at least) has an error in the FocusAButton function too
+// this could be fixed as follows ...
+//if (window.FocusAButton) {
+// window.FocusAButton = new Function('return true');
+//}
+// however, ns6.0 then crashes completely when the mouse moves over a link, so don't bother
+// Hot Potatoes quiz sniffing
+// === v3 ===
+// JBC uses "QuizForm", which contains elements called "Q*_**" (* and ** start at 1)
+// JCloze uses "Cloze" form
+// JCross uses "Crossword" form
+// JMatch uses "QuizForm", which contains elements called "1,2,3..x" and "x+1,x+2...",
+// and "CheckForm" form, which contains an element called "ScoreBox"
+// it is also the only HP quiz type to use an array called "CorrectAnswers"
+// JQuiz uses "QForm*" forms (* starts at 1), which each contain an element called "Guess"
+// === v4 ===
+// JBC uses "QForm" form in "QuestionDiv", which contains elements called "FB* (* starts at 0)"
+// JCloze uses "Cloze" form in "QuestionDiv"
+// JCross uses "Crossword" form in "CWDiv"
+// JMatch uses "ExCheck" form in "TitleDiv"
+// (no JMix in hp4)
+// JQuiz uses "QForm" form in "QuestionDiv", which contains an element called "Answer"
+// === v5 ===
+// JBC uses "QForm" form, which contains elements called "FB_*_**" (* and ** start at 0)
+// JCloze uses "Cloze" form
+// JCross writes out "AnswerForm" from a variable called "GetAnswerOpener"
+// HP5.3: uses "AnswerForm" in "BottomFrame"
+// HP5.5: uses "AnswerForm" in "TopFrame", but it is only there when an answer is being input
+// JMatch uses "QForm" form, which contains elements called "sel*" (which disappear by the time the quiz is finished)
+// JMix uses "ButtonForm"
+// JQuiz uses "QForm*" and "Buttons*" (one for each question)
+// === v6 ===
+// JBC uses "QForm" form (elements have no name or id)
+// JCloze uses "Cloze" form (elements have no name or id)
+// JCross does not use any forms,
+// HP5: has "GridDiv" in "MainDiv"
+// HP6: has "Clues" table in "MainDiv"
+// JMatch has "MatchDiv" in "MainDiv"
+// HP5: uses "QForm" form, which contains elements called "sel*"
+// HP6: uses "QForm" form, which contains elements called "s*_**"
+// JMix does not use any forms, but has "SegmentDiv" in "MainDiv"
+// JQuiz
+// HP5: uses "QForm" form, which contains an element called "Guess"
+// HP6: has "Questions" ordered list in "MainDiv"
+// === v6+ ===
+// JMatch has DIVs called "D*" and "F*" (* starts at 0)
+// JMix has DIVs called "D*" and "Drop*" (* starts at 0)
+// useful sniffing tools (Cut and Paste to browser address box)
+//javascript:var s="";var x=new quiz_obj();for(X in x)s+=","+X+"="+x[X];alert(s.substring(1));
+//javascript:var s="";var x=document.layers;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))
+//javascript:var s="";var x=document.forms;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].id;alert(s.substring(1))
+//javascript:var s="";var x=document.forms.QForm.elements;for(var i=0;i<x.length;i++)s+=","+x[i].name;alert(s.substring(1))
+function hpDetectQuiz() {
+ // "sniff" (=detect) the quiz's type and intended browser version
+ // and cache the values in a global variable called "quiz"
+ // Hot Potatoes version
+ // 5 : HP5.3 (mac) or HP5.5 (win)
+ // 6 : HP6.0 (mac) or HP6.0 (win)
+ // intended browser version
+ // 3 : ns3, ie3 (frames)
+ // 4 : ns4, ie4 (cross browser dhtml)
+ // 5 : ie5 (frames, send results via CGI)
+ // 6 : ie6, op7, gecko (w3 standards)
+ // 6.1 : "drag and drop" versions of JMatch and JMix v6
+ // quiz type
+ // 0 : unknown
+ // 1 : jbc
+ // 2 : jcloze
+ // 3 : jcross
+ // 4 : jmatch
+ // 5 : jmix
+ // 6 : jquiz
+ // 7 : rhubarb (TexToys)
+ // 8 : Sequitur (TexToys)
+ // rottmeier quiz type
+ // 1 : drop-down (JCloze)
+ // 2 : find-it (JCloze)
+ // shortcut to window object
+ var w = window;
+ // create the global "quiz" object, if necessary
+ if (!w.quiz) w.quiz = new Object();
+ // Hot Potatoes version
+ // HP6 v6: Client()
+ // HP5 v4-v5: BrowserCheck()
+ // v3: WinStringToMac() [JCloze, JCross, JQuiz]
+ // v3: winrightchar [JBC, JMatch]
+ // v3: DownTime() [JBC, JCloze, JQuiz]
+ if (!quiz.hp) {
+ quiz.hp = (w.Client) ? 6 : (w.BrowserCheck) ? 5 : (w.WinStringToMac || w.winrightchar) ? 5 : -1;
+ }
+ // check the version and type are not already set
+ if (!quiz.v || !quiz.t) {
+ // initialize version and type
+ var v = 0;
+ var t = 0;
+ // set shortcuts to DOM objects
+ var d = document;
+ var f = d.forms;
+ if (f.QuizForm && f.CheckForm && w.CorrectAnswers) {
+ v = 3;
+ t = 4; // jmatch
+ } else if (w.FeedbackFrame && w.CodeFrame) {
+ v = 3;
+ f = CodeFrame.document.forms;
+ t = (f.QuizForm) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.QForm1) ? 6 : 0;
+ } else if (w.DynLayer) {
+ v = 4;
+ if (d.layers) {
+ // for NS4, adjust "f" to point to a forms object in a layer
+ var lyr = d.QuestionDiv || d.CWDiv || d.TitleDiv || null;
+ if (lyr) f = lyr.document.forms;
+ }
+ t = (f.QForm && f.QForm.FB0) ? 1 : (f.Cloze) ? 2 : (f.Crossword) ? 3 : (f.ExCheck) ? 4 : (f.QForm && f.QForm.Answer) ? 6 : 0;
+ } else if (w.TopFrame && w.BottomFrame) {
+ v = 5;
+ f = BottomFrame.document.forms;
+ t = (f.QForm && f.QForm.elements[0].name.substring(0,3)=='FB_') ? 1 : (f.Cloze) ? 2 : (w.GetAnswerOpener && GetAnswerOpener.indexOf('AnswerForm')>=0) ? 3 : (f.QForm && w.RItems) ? 4 : (f.ButtonForm) ? 5 : (f.QForm0 && f.Buttons0) ? 6 : 0;
+ } else if (hpObj(d, 'MainDiv')) {
+ v = 6;
+ var obj = (f.QForm) ? f.QForm.elements : null;
+ t = (obj && obj.length>0 && obj[0].id=='') ? 1 : (f.Cloze) ? 2 : (hpObj(d, 'GridDiv') || hpObj(d, 'Clues')) ? 3 : hpObj(d, 'MatchDiv') ? 4 : hpObj(d, 'SegmentDiv') ? 5 : ((f.QForm && f.QForm.Guess) || hpObj(d, 'Questions')) ? 6 : 0;
+ } else if (hpObj(d, 'D0')) {
+ v = 6.1; // drag and drop (HP5 and HP6)
+ t = (hpObj(d, 'F0')) ? 4 : (hpObj(d, 'Drop0')) ? 5 : 0;
+ } else if (w.Words && f.Rhubarb) {
+ v = 6;
+ t = 7; // rhubarb (TexToys)
+ } else if (w.Segments && hpObj(d, 'Story')) {
+ v = 6;
+ t = 8; // sequitur (TexToys)
+ }
+ quiz.v = v; // intended browser version
+ quiz.t = t; // quiz type
+ }
+}
+function hpRottmeier() {
+ hpDetectQuiz();
+ if (typeof(quiz.r)=='undefined') { // first-time only
+ quiz.r = 0;
+ if (quiz.t==2) { // JCloze
+ if (quiz.hp==5) { // HP5
+ // ??
+ } else if (quiz.hp==6) { // HP6
+ if (window.Create_StateArray) { // Rottmeier
+ var obj = new Create_StateArray();
+ if (typeof(obj.GapLocked)=='boolean') {
+ quiz.r = 1; // drop-down (v2.4)
+ } else if (typeof(obj.ErrorFound)=='boolean') {
+ if (typeof(obj.GapSolved)!='boolean') {
+ quiz.r = 2.1; // find-it (v3.1a)
+ } else {
+ quiz.r = 2.2; // find-it (v3.1b)
+ }
+ }
+ obj = null; // prevents memory leakage on some versions of IE
+ }
+ }
+ }
+ }
+ return quiz.r;
+}
+function hpVersion() {
+ hpDetectQuiz();
+ return quiz.hp;
+}
+function hpQuizType() {
+ hpDetectQuiz();
+ return quiz.t;
+}
+function hpQuizVersion() {
+ hpDetectQuiz();
+ return quiz.v;
+}
+function hpScoreEngine(score_i, a, s, aa, ss, count_c, count_i) {
+ // calculate the score for the quiz so far
+ // score_i : amount by which to increment "score"
+ // a : outer array
+ // s : condition, if any, on outer array (=a)
+ // if true, the score will be incremented by "score_i"
+ // aa : inner array, if any
+ // ss : condition, if any, on inner array (=aa)
+ // count_c : condition, if any, on which "count" is to be incremented
+ // count_i : amount by which to increment "count"
+ // "a" and "aa" may be passed as arrays or strings containing the name of an array
+ // "s" and "ss" are strings containing an expression to be eval(uated)
+ // "score_i", "count_i" and "count_c" strings containing an expression to be eval(uated)
+ var score = 0;
+ var count = 0;
+ // set default condition to increment "count", and amount by which to increment the count
+ if (count_c==null) count_c = "true";
+ if (count_i==null) count_i = "1";
+ // set length of outer array. if any
+ var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;
+ // loop through outer array
+ for (var i=0; i<l; i++) {
+ if (s==null && ss==null) {
+ score += eval(score_i);
+ if (eval(count_c)) count += eval(count_i);
+ } else if (s) {
+ score += eval(s) ? eval(score_i) : 0;
+ if (eval(count_c)) count += eval(count_i);
+ } else if (ss) {
+ // set length of inner array, if any
+ var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;
+ // loop through inner array. checking inner condition
+ for (var ii=0; ii<ll; ii++) {
+ score += eval(ss) ? eval(score_i) : 0;
+ if (eval(count_c)) count += eval(count_i);
+ }
+ }
+ }
+ if (count) {
+ // get p(enalties) for JCross and JMatch (and JMix ?)
+ if (window.Penalties) {
+ score -= (Penalties - (hpFinished() ? 0 : 1));
+ }
+ // adjust count for Find-It 3a and 3b
+ if (window.TotWrongChoices) {
+ if (window.CheckText && !window.CheckAnswers) { // Find-It 3a
+ // this seems a little odd, but will replicate behavior of CalculateScore()
+ count = score + TotWrongChoices;
+ } else {
+ count += TotWrongChoices;
+ }
+ }
+ score = Math.floor(100*score/count);
+ if (score<0) { // just in case
+ score = 0;
+ }
+ }
+ return score;
+}
+function hpScore() {
+ var x = ''; // score
+ var hp = hpVersion();
+ var t = hpQuizType();
+ var v = hpQuizVersion();
+ if (t==1) { // jbc
+ if (v==3) x = hpScoreEngine(1, DoneStatus, "i>0 && a[i]=='0'"); // doesn't work
+ else if (v==4) x = hpScoreEngine(1, DoneStatus, "a[i]==0"); // doesn't work
+ else if (v==5 || v==6) x = hpScoreEngine("a[i][3]", Status, "a[i][3]");
+ } else if (t==2) { // jcloze
+ if (v==3 || v==4) x = hpScoreEngine("a[i]", Scores);
+ else if (hp==5) x = hpScoreEngine("a[i][3]", State); // v==5 && v==6
+ else if (hp==6) {
+ var r = hpRottmeier();
+ if (r==0) x = x = hpScoreEngine("a[i].ItemScore", State);
+ else if (r==1) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapLocked"); // dropdown
+ else if (r==2.1) x = hpScoreEngine(1, GapList, "a[i][1].ErrorFound"); // Find-It 3a
+ else if (r==2.2) x = hpScoreEngine("a[i][1].Score", GapList, "a[i][1].GapSolved"); // Find-It 3b
+ }
+ } else if (t==3) { // jcross
+ if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");
+ else if (v==4) x = hpScoreEngine(1, WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0)==a[i].charAt(0)");
+ else if (v==5 || v==6) x = hpScoreEngine(1, L, "", "L[i]", "L[i][ii] && L[i][ii]==G[i][ii]", "L[i][ii]");
+ } else if (t==4) { // jmatch
+ if (v==3) x = hpScoreEngine(1, CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex==a[i]");
+ else if (v==4) x = hpScoreEngine(1, Draggables, "a[i].correct=='1'");
+ else if (v==5) x = hpScoreEngine(1, I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]==1");
+ else if (v==6) x = hpScoreEngine(1, Status, "Status[i][0]==1");
+ else if (v==5.1 || v==6.1) x = hpScoreEngine(1, D, "D[i][2]==D[i][1] && D[i][2]>0", "", "", "i<F.length");
+ } else if (t==5) { // jmix
+ // there was no v3 or v4 of JMix
+ if (v==5 || v==6 || v==6.1) x = Math.floor(100*(Segments.length-Penalties)/Segments.length);
+ } else if (t==6) { // jquiz
+ if (hp==5) {
+ if (v==3 || v==4) x = hpScoreEngine("a[i][4]/10", State, "a[i][0]==1");
+ else if (v==5 || v==6) x = hpScoreEngine("a[i][4]/10", Status, "a[i][0]==1", "", "", "true", "1");
+ } else if (hp==6) {
+ if (v==6) x = hpScoreEngine("I[i][0]*a[i][0]", State, "a[i]&&a[i][0]>=0", "", "", "a[i]", "I[i][0]");
+ }
+ } else if (t==7) { // rhubarb
+ if (v==6) {
+ x = Math.floor(100*Correct/TotalWords);
+ }
+ } else if (t==8) { // sequitur
+ if (v==6) {
+ var myTotalPoints = TotalPoints - (hpFinished() ? 0 : (OptionsThisQ-1));
+ x = Math.floor(100*ScoredPoints/myTotalPoints);
+ }
+ }
+ return x; // result
+}
+function hpFinishedEngine(a, s, aa, ss) {
+ // determine whether or not all quistions in a quiz are finished
+ // a : outer array
+ // s : condition, if any, on outer array
+ // if true for any element in "a", the quiz is NOT finished
+ // aa : inner array, if any
+ // ss : condition, if any, on inner array
+ // if true for any element in "aa", the quiz is NOT finished
+ // the arrays "a" and "aa" may be passed as arrays or strings to be eval(uated)
+ // the conditions "s" and "ss" are specified as strings to be eval(uated)
+ // assume a positive result
+ var x = true;
+ // set length of outer array. if any
+ var l = (typeof(a)=="string") ? eval(a + ".length") : a ? a.length : 0;
+ // loop through outer array
+ for (var i=0; i<l; i++) {
+ // do outer condition, if any
+ if (s && eval(s)) x = false;
+ // set length of inner array, if any
+ var ll = (typeof(aa)=="string") ? eval(aa + ".length") : aa ? aa.length : 0;
+ // loop through inner array. checking inner condition
+ for (var ii=0; ii<ll; ii++) {
+ if (ss && eval(ss)) x = false;
+ }
+ }
+ return x;
+}
+function hpTimedOut() {
+ // v5 uses "min" and "sec"
+ // v6 uses Seconds
+ return (typeof(self.Seconds)=='number' && Seconds==0) || (typeof(self.min)=='number' && min==0 && typeof(self.sec)=='number' && sec==0);
+}
+function hpFinished() {
+ // assume false result
+ var x = false;
+ var hp = hpVersion();
+ var t = hpQuizType();
+ var v = hpQuizVersion();
+ if (t==1) { // jbc
+ if (v==3) x = hpFinishedEngine(DoneStatus, "i>0 && a[i]=='0'");
+ else if (v==4) x = hpFinishedEngine(DoneStatus, "a[i]==0");
+ else if (v==5 || v==6) x = hpFinishedEngine(Status, "a[i][0]==0");
+ } else if (t==2) { // jcloze
+ var r = hpRottmeier();
+ if (r==1) x = hpFinishedEngine(GapList, "a[i][1].GapLocked==false"); // drop-down
+ else if (r==2.1) x = hpFinishedEngine(GapList, "a[i][1].ErrorFound==false"); // find-it 3a
+ else if (r==2.2) x = hpFinishedEngine(GapList, "a[i][1].GapSolved==false"); // find-it 3b
+ else if (v==3 || v==4 || v==5 || v==6) x = hpFinishedEngine(I, "CheckAnswer(i)==-1");
+ // also: else if (v==5 || v==6) x = hpFinishedEngine(State, "a[i][4]!=1")
+ } else if (t==3) { // jcross
+ if (v==3) x = hpFinishedEngine(document.Crossword.elements, "ConvertCase(is.mac?unescape(MacStringToWin(a[i].value)):a[i].value,1)!=Letters[i]");
+ else if (v==4) x = hpFinishedEngine(WinLetters, "ConvertCase(GetBoxValue(i),1).charAt(0) != a[i].charAt(0)");
+ else if (v==5 || v==6) x = hpFinishedEngine(L, "", "L[i]", "L[i][ii] && L[i][ii]!=G[i][ii]");
+ } else if (t==4) { // jmatch
+ if (v==3) x = hpFinishedEngine(CorrectAnswers, "document.QuizForm.elements[i*2].selectedIndex != a[i]");
+ else if (v==4) x = hpFinishedEngine(Draggables, "a[i].correct!='1'");
+ else if (v==5) x = hpFinishedEngine(I, "I[i][2]<1 && I[i][0].length>0 && Status[i][0]<1 && GetAnswer(i)!=I[i][3]");
+ else if (v==6) x = hpFinishedEngine(Status, "Status[i][0]<1");
+ else if (v==5.1 || v==6.1) x = hpFinishedEngine(D, "", F, "F[ii][1]==D[i][1]&&D[i][1]!=D[i][2]");
+ } else if (t==5) { // jmix
+ // there was no v3 or v4 of JMix
+ if (v==5 || v==6 || v==6.1) x = !hpFinishedEngine(Answers, "a[i].join(',')=='" + GuessSequence.join(',') + "'");
+ } else if (t==6) { // jquiz
+ if (v==3 || v==4) x = hpFinishedEngine(State, "a[i][0]==0");
+ else if (v==5 || v==6) {
+ if (hp==5) x = hpFinishedEngine(Status, "a[i][0]<1");
+ else if (hp==6) x = hpFinishedEngine(State, "a[i] && a[i][0]<0");
+ }
+ } else if (t==7) { // rhubarb
+ if (v==6) x = hpFinishedEngine(DoneList, "a[i]==1");
+ } else if (t==8) { // sequitur
+ if (v==6) x = (CurrentNumber==TotalSegments || AllDone);
+ }
+ return x;
+}
+function hpObj(d, id) {
+ return d.getElementById ? d.getElementById(id) : d.all ? d.all[id] : d[id];
+}
+function GetViewportHeight() {
+ if (window.innerHeight) {
+ return innerHeight;
+ } else {
+ if (hpIsStrict()) {
+ return document.documentElement.clientHeight;
+ } else {
+ return document.body.clientHeight;
+ }
+ }
+}
+function hpIsStrict() {
+ if (!window.hpStrictIsSet) {
+ window.hpStrictIsSet = true;
+ window.hpStrict = false;
+ var s = document.compatMode;
+ if (s && s=="CSS1Compat") { // ie6
+ window.hpStrict = true;
+ } else {
+ var obj = document.doctype;
+ if (obj) {
+ var s = obj.systemId || obj.name; // n6 || ie5mac
+ if (s && s.indexOf("strict.dtd") >= 0) {
+ window.hpStrict = true;
+ }
+ }
+ }
+ }
+ return window.hpStrict;
+}
+// **************
+// initialization
+// **************
+hpInterceptFeedback();
+hpInterceptHints();
+hpInterceptClues();
+hpInterceptChecks();
+function hpFindForm(formname, w) {
+ if (w==null) w = self;
+ var f = w.document.forms[formname];
+ if (f==null && w.frames) {
+ for (var i=0; i<w.frames.length; i++) {
+ f = hpFindForm(formname, w.frames[i]);
+ if (f) break;
+ }
+ }
+ return f;
+}
+function Finish(quizstatus) {
+ var mark = hpScore();
+ window.hpForm = hpFindForm('store');
+ if (hpForm) { // LMS
+ hpForm.starttime.value = getTime(Start_Time);
+ hpForm.endtime.value = getTime();
+ hpForm.mark.value = mark;
+ hpForm.detail.value = '<?xml version="1.0"?><hpjsresult><fields>'+GetQuestionDetails()+'</fields></hpjsresult>';
+ if (hpForm.status) {
+ if (!quizstatus) {
+ // 4=completed, 3=abandoned, 2=timed-out or 1=in-progress
+ quizstatus = hpFinished() ? 4 : hpTimedOut() ? 2 : 1;
+ }
+ hpForm.status.value = quizstatus;
+ }
+ if (!window.hpQuizResultsSent) {
+ if (hpForm.status && quizstatus==4) {
+ window.hpQuizResultsSent = true;
+ }
+ if (quizstatus==4) { // completed
+ // wait 2 seconds for student to see feedback
+ setTimeout("hpForm.submit();", 2000);
+ } else {
+ hpForm.submit();
+ }
+ }
+ } else if (hpFinished()) {
+ SendAllResults(mark);
+ }
+}
+// create form to send results
+if (DB[7] && DB[8] && !is_LMS()) {
+ ResultForm = ''
+ + '<html><body>'
+ + '<form name="Results" action="" method="post" enctype="x-www-form-encoded">'
+ + hpHiddenField('recipient', '')
+ + hpHiddenField('subject', '')
+ + hpHiddenField('Exercise', '')
+ + hpHiddenField('realname', '')
+ + hpHiddenField('Score', '')
+ + hpHiddenField('Start_Time', '')
+ + hpHiddenField('End_Time', '')
+ + hpHiddenField('title', 'Thanks!')
+ + '</form>'
+ + '</body></html>'
+ ;
+}
+// reassign the StartUp function
+var p = getPrompt(window.GetUserName || window.StartUp);
+var c = getStartUpCode(window.StartUp);
+if (p && c) {
+ window.StartUp = new Function('QuizLogin("' + p + '")');
+ window.StartQuiz = new Function(c);
+ // "QuizLogin" finshes by calling "StartQuiz"
+}
+// reassign the SendResults function
+window.SendResults = SendAllResults;
+// set start time
+var Start_Time = new Date();
+//-->
-<?php // $Id$\r
-/// Overview report just displays a big table of all the attempts\r
-class hotpot_report extends hotpot_default_report {\r
- function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {\r
- global $CFG;\r
- // create the tables\r
- $tables = array();\r
- $this->create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);\r
- // print the tables\r
- $this->print_report($course, $hotpot, $tables, $options);\r
- return true;\r
- }\r
- function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {\r
- global $CFG;\r
- $is_html = ($options['reportformat']=='htm');\r
- // time and date format strings // date format strings\r
- $strftimetime = '%H:%M:%S';\r
- $strftimedate = get_string('strftimedate');\r
- // get the current time and max execution time\r
- $start_report_time = microtime();\r
- $max_execution_time = ini_get('max_execution_time');\r
- $correct = get_string('reportcorrectsymbol', 'hotpot');\r
- $wrong = get_string('reportwrongsymbol', 'hotpot');\r
- $nottried = get_string('reportnottriedsymbol', 'hotpot');\r
- // shortcuts for font tags\r
- $blank = $is_html ? ' ' : "";\r
- // store question count\r
- $questioncount = count($questions);\r
- // array to map columns onto question ids ($col => $id)\r
- $questionids = array_keys($questions);\r
- // store exercise type\r
- $exercisetype = $this->get_exercisetype($questions, $questionids, $blank);\r
- // initialize details ('events' must go last)\r
- $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events');\r
- // initialize $table\r
- unset($table);\r
- $table->border = 1;\r
- $table->width = '100%';\r
- // initialize legend, if necessary\r
- if (!empty($options['reportshowlegend'])) {\r
- $table->legend = array();\r
- }\r
- // start $table headings\r
- $this->set_head($options, $table, 'exercise');\r
- $this->set_head($options, $table, 'user');\r
- $this->set_head($options, $table, 'attempt');\r
- $this->set_head($options, $table, 'click');\r
- // store clicktype column number\r
- $clicktype_col = count($table->head)-1;\r
- // finish $table headings\r
- $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount);\r
- $this->set_head($options, $table, 'totals', $exercisetype);\r
- // set align and wrap\r
- $this->set_align_and_wrap($table);\r
- // is link to review allowed?\r
- $allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));\r
- // initialize array of data values\r
- $this->data = array();\r
- // set exercise data values\r
- $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank);\r
- // add details of users' responses\r
- foreach ($users as $user) {\r
- $this->set_data_user($options, $course, $user);\r
- unset($clickreportid);\r
- foreach ($user->attempts as $attempt) {\r
- // initialize totals for\r
- $click = array(\r
- 'qnumber' => array(),\r
- 'correct' => array(),\r
- 'wrong' => array(),\r
- 'answers' => array(),\r
- 'hints' => array(),\r
- 'clues' => array(),\r
- 'changes' => array(),\r
- 'checks' => array(),\r
- 'events' => array(),\r
- 'score' => array(),\r
- 'weighting' => array()\r
- );\r
- $clicktypes = array();\r
- // is the start of a new attempt?\r
- // (clicks in the same attempt have the same clickreportid)\r
- if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) {\r
- $clickcount = 1;\r
- $clickreportid = $attempt->clickreportid;\r
- // initialize totals for all clicks in this attempt\r
- $clicks = $click; // $click has just been initialized\r
- $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank);\r
- }\r
- $cells = array();\r
- $this->set_data($cells, 'exercise');\r
- $this->set_data($cells, 'user');\r
- $this->set_data($cells, 'attempt');\r
- // get responses to questions in this attempt\r
- foreach ($attempt->responses as $response) {\r
- // set $q(uestion number)\r
- $q = array_search($response->question, $questionids);\r
- $click['qnumber'][$q] = true;\r
- // was this question answered correctly?\r
- if ($answer = hotpot_strings($response->correct)) {\r
- // mark the question as correctly answered\r
- if (empty($clicks['correct'][$q])) {\r
- $click['correct'][$q] = true;\r
- $clicks['correct'][$q] = true;\r
- }\r
- // unset 'wrong' flags, if necessary\r
- if (isset($click['wrong'][$q])) {\r
- unset($click['wrong'][$q]);\r
- }\r
- if (isset($clicks['wrong'][$q])) {\r
- unset($clicks['wrong'][$q]);\r
- }\r
- // otherwise, was the question answered wrongly?\r
- } else if ($answer = hotpot_strings($response->wrong)) {\r
- // mark the question as wrongly answered\r
- $click['wrong'][$q] = true;\r
- $clicks['wrong'][$q] = true;\r
- } else { // not correct or wrong (curious?!)\r
- unset($answer);\r
- }\r
- if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) {\r
- $click['score'][$q] = $response->score;\r
- $clicks['score'][$q] = $response->score;\r
- $weighting = isset($response->weighting) ? $response->weighting : 100;\r
- $click['weighting'][$q] = $weighting;\r
- $clicks['weighting'][$q] =$weighting;\r
- }\r
- foreach($details as $detail) {\r
- switch ($detail) {\r
- case 'answers':\r
- if (isset($answer) && is_string($answer) && !empty($answer)) {\r
- $click[$detail][$q] = $answer;\r
- }\r
- break;\r
- case 'hints':\r
- case 'clues':\r
- case 'checks':\r
- if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) {\r
- if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) {\r
- $click[$detail][$q] = $response->$detail;\r
- }\r
- }\r
- break;\r
- }\r
- } // end foreach $detail\r
- } // end foreach $response\r
- $click['types'] = array();\r
- $this->data['details'] = array();\r
- foreach($details as $detail) {\r
- for ($q=0; $q<$questioncount; $q++) {\r
- switch ($detail) {\r
- case 'status':\r
- if (isset($clicks['correct'][$q])) {\r
- $this->data['details'][] = $correct;\r
- } else if (isset($clicks['wrong'][$q])) {\r
- $this->data['details'][] = $wrong;\r
- } else if (isset($click['qnumber'][$q])) {\r
- $this->data['details'][] = $nottried;\r
- } else { // this question did not appear in this attempt\r
- $this->data['details'][] = $blank;\r
- }\r
- break;\r
- case 'answers':\r
- case 'hints':\r
- case 'clues':\r
- case 'checks':\r
- if (!isset($clicks[$detail][$q])) {\r
- if (!isset($click[$detail][$q])) {\r
- $this->data['details'][] = $blank;\r
- } else {\r
- $clicks[$detail][$q] = $click[$detail][$q];\r
- if ($detail=='answers') {\r
- $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]);\r
- }\r
- $this->data['details'][] = $click[$detail][$q];\r
- $this->update_event_count($click, $detail, $q);\r
- }\r
- } else {\r
- if (!isset($click[$detail][$q])) {\r
- $this->data['details'][] = $blank;\r
- } else {\r
- $difference = '';\r
- if ($detail=='answers') {\r
- if ($click[$detail][$q] != $clicks[$detail][$q]) {\r
- $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/';\r
- $difference = preg_replace($pattern, '', $click[$detail][$q], 1);\r
- }\r
- } else { // hints, clues, checks\r
- if ($click[$detail][$q] > $clicks[$detail][$q]) {\r
- $difference = $click[$detail][$q] - $clicks[$detail][$q];\r
- }\r
- }\r
- if ($difference) {\r
- $clicks[$detail][$q] = $click[$detail][$q];\r
- $click[$detail][$q] = $difference;\r
- if ($detail=='answers') {\r
- $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]);\r
- }\r
- $this->data['details'][] = $difference;\r
- $this->update_event_count($click, $detail, $q);\r
- } else {\r
- unset($click[$detail][$q]);\r
- $this->data['details'][] = $blank;\r
- }\r
- }\r
- }\r
- break;\r
- case 'changes':\r
- case 'events':\r
- if (empty($click[$detail][$q])) {\r
- $this->data['details'][] = $blank;\r
- } else {\r
- $this->data['details'][] = $click[$detail][$q];\r
- }\r
- break;\r
- default:\r
- // do nothing\r
- break;\r
- } // end switch\r
- } // for $q\r
- } // foreach $detail\r
- // set data cell values for\r
- $this->set_data_click(\r
- $allow_review ? '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$clickcount.'</a>' : $clickcount,\r
- trim(userdate($attempt->timefinish, $strftimetime)),\r
- $exercisetype,\r
- $click\r
- );\r
- $this->set_data($cells, 'click');\r
- $this->set_data($cells, 'details');\r
- $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt);\r
- $this->set_data($cells, 'totals');\r
- $table->data[] = $cells;\r
- $clickcount++;\r
- } // end foreach $attempt\r
- // insert 'tabledivider' between users\r
- $table->data[] = 'hr';\r
- } // end foreach $user\r
- // remove final 'hr' from data rows\r
- array_pop($table->data);\r
- if ($is_html && $CFG->hotpot_showtimes) {\r
- $count = count($users);\r
- $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime()));\r
- print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)<hr size="1" noshade="noshade" />'."\n";\r
- }\r
- $tables[] = &$table;\r
- $this->create_legend_table($tables, $table);\r
- } // end function\r
- function get_exercisetype(&$questions, &$questionids, &$blank) {\r
- if (empty($questions)) {\r
- $type = $blank;\r
- } else {\r
- switch ($questions[$questionids[0]]->type) {\r
- case HOTPOT_JCB:\r
- $type = "JCB";\r
- break;\r
- case HOTPOT_JCLOZE :\r
- $type = "JCloze";\r
- break;\r
- case HOTPOT_JCROSS :\r
- $type = "JCross";\r
- break;\r
- case HOTPOT_JMATCH :\r
- $type = "JMatch";\r
- break;\r
- case HOTPOT_JMIX :\r
- $type = "JMix";\r
- break;\r
- case HOTPOT_JQUIZ :\r
- $type = "JQuiz";\r
- break;\r
- case HOTPOT_TEXTOYS_RHUBARB :\r
- $type = "Rhubarb";\r
- break;\r
- case HOTPOT_TEXTOYS_SEQUITUR :\r
- $type = "Sequitur";\r
- break;\r
- default:\r
- $type = $blank;\r
- }\r
- }\r
- return $type;\r
- }\r
- function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) {\r
- if (empty($table->head)) {\r
- $table->head = array();\r
- }\r
- switch ($zone) {\r
- case 'exercise':\r
- array_push($table->head,\r
- get_string('reportcoursename', 'hotpot'),\r
- get_string('reportsectionnumber', 'hotpot'),\r
- get_string('reportexercisenumber', 'hotpot'),\r
- get_string('reportexercisename', 'hotpot'),\r
- get_string('reportexercisetype', 'hotpot'),\r
- get_string('reportnumberofquestions', 'hotpot')\r
- );\r
- break;\r
- case 'user':\r
- array_push($table->head,\r
- get_string('reportstudentid', 'hotpot'),\r
- get_string('reportlogindate', 'hotpot'),\r
- get_string('reportlogintime', 'hotpot'),\r
- get_string('reportlogofftime', 'hotpot')\r
- );\r
- break;\r
- case 'attempt':\r
- array_push($table->head,\r
- get_string('reportattemptnumber', 'hotpot'),\r
- get_string('reportattemptstart', 'hotpot'),\r
- get_string('reportattemptfinish', 'hotpot')\r
- );\r
- break;\r
- case 'click':\r
- array_push($table->head,\r
- get_string('reportclicknumber', 'hotpot'),\r
- get_string('reportclicktime', 'hotpot'),\r
- get_string('reportclicktype', 'hotpot')\r
- );\r
- break;\r
- case 'details':\r
- foreach($details as $detail) {\r
- if ($exercisetype=='JQuiz' && $detail=='clues') {\r
- $detail = 'showanswer';\r
- }\r
- $detail = get_string("report$detail", 'hotpot');\r
- for ($i=0; $i<$questioncount; $i++) {\r
- $str = get_string('questionshort', 'hotpot', $i+1);\r
- if ($i==0 || $options['reportformat']!='htm') {\r
- $str = "$detail $str";\r
- }\r
- $table->head[] = $str;\r
- }\r
- }\r
- break;\r
- case 'totals':\r
- $reportpercentscore =get_string('reportpercentscore', 'hotpot');\r
- if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less)\r
- $reportpercentscore = str_replace('%', '%%', $reportpercentscore);\r
- }\r
- array_push($table->head, \r
- get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')),\r
- get_string('reportthisclick', 'hotpot', $reportpercentscore),\r
- get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')),\r
- get_string('reportsofar', 'hotpot', $reportpercentscore),\r
- get_string('reporthotpotscore', 'hotpot')\r
- );\r
- break;\r
- } // end switch\r
- }\r
- function set_align_and_wrap(&$table) {\r
- $count = count($table->head);\r
- for ($i=0; $i<$count; $i++) {\r
- if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) {\r
- // numeric (and short text) columns\r
- $table->align[] = 'center';\r
- $table->wrap[] = '';\r
- } else {\r
- // text columns\r
- $table->align[] = 'left';\r
- $table->wrap[] = 'nowrap';\r
- }\r
- }\r
- }\r
- function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) {\r
- // get exercise details (course name, section number, activity number, quiztype and question count)\r
- $record = get_record("course_sections", "id", $cm->section);\r
- $this->data['exercise'] = array(\r
- 'course' => $course->shortname,\r
- 'section' => empty($record) ? $blank : $record->section+1,\r
- 'number' => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1,\r
- 'name' => $hotpot->name,\r
- 'type' => $this->get_exercisetype($questions, $questionids, $blank),\r
- 'questioncount' => $questioncount\r
- );\r
- }\r
- function set_data_user(&$options, &$course, &$user) {\r
- global $CFG;\r
- // shortcut to first attempt record (which also hold user info)\r
- $attempt = &$user->attempts[0];\r
- $idnumber = $attempt->idnumber;\r
- if (empty($idnumber)) {\r
- $idnumber = fullname($attempt);\r
- }\r
- if ($options['reportformat']=='htm') {\r
- $idnumber = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.$idnumber.'</a>';\r
- }\r
- $this->data['user'] = array(\r
- 'idnumber' => $idnumber,\r
- );\r
- }\r
- function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) {\r
- global $CFG;\r
- $records = get_records_sql_menu("\r
- SELECT userid, MAX(time) AS logintime\r
- FROM {$CFG->prefix}log\r
- WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart\r
- GROUP BY userid\r
- ");\r
- if (empty($records)) {\r
- $logindate = $blank;\r
- $logintime = $blank;\r
- } else {\r
- $logintime = $records[$attempt->userid];\r
- $logindate = trim(userdate($logintime, $strftimedate));\r
- $logintime = trim(userdate($logintime, $strftimetime));\r
- }\r
- $records = get_records_sql_menu("\r
- SELECT userid, MIN(time) AS logouttime\r
- FROM {$CFG->prefix}log\r
- WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish \r
- GROUP BY userid\r
- ");\r
- if (empty($records)) {\r
- $logouttime = $blank;\r
- } else {\r
- $logouttime = $records[$attempt->userid];\r
- $logouttime = trim(userdate($logouttime, $strftimetime));\r
- }\r
- $this->data['attempt'] = array(\r
- 'logindate' => $logindate,\r
- 'logintime' => $logintime,\r
- 'logouttime' => $logouttime,\r
- 'number' => $attempt->attempt,\r
- 'start' => trim(userdate($attempt->timestart, $strftimetime)),\r
- 'finish' => trim(userdate($attempt->cr_timefinish, $strftimetime)),\r
- );\r
- }\r
- function set_data_click($number, $time, $exercisetype, $click) {\r
- $types = array();\r
- foreach (array_keys($click['types']) as $type) {\r
- if ($exercisetype=='JQuiz' && $type=='clues') {\r
- $type = 'showanswer';\r
- } else {\r
- // remove final 's'\r
- $type = substr($type, 0, strlen($type)-1);\r
- }\r
- // $types[] = get_string($type, 'hotpot');\r
- $types[] = $type;\r
- }\r
- $this->data['click'] = array(\r
- 'number' => $number,\r
- 'time' => $time,\r
- 'type' => empty($types) ? '??' : implode(',', $types)\r
- );\r
- }\r
- function set_data_totals(&$click, &$clicks, &$questioncount, &$blank, &$attempt) {\r
- $count= array(\r
- 'click' => array(\r
- 'correct' => count($click['correct']),\r
- 'wrong' => count($click['wrong']),\r
- 'answers' => count($click['answers']),\r
- 'hints' => array_sum($click['hints']),\r
- 'clues' => array_sum($click['clues']),\r
- 'events' => array_sum($click['events']),\r
- 'score' => array_sum($click['score']),\r
- 'maxscore' => array_sum($click['weighting']),\r
- ),\r
- 'clicks' => array(\r
- 'correct' => count($clicks['correct']),\r
- 'wrong' => count($clicks['wrong']),\r
- 'answers' => count($clicks['answers']),\r
- 'hints' => array_sum($clicks['hints']),\r
- 'clues' => array_sum($clicks['clues']),\r
- 'score' => array_sum($clicks['score']),\r
- 'maxscore' => array_sum($clicks['weighting']),\r
- )\r
- );\r
- foreach ($count as $period=>$values) {\r
- $count[$period]['nottried'] = $questioncount - ($values['correct'] + $values['wrong']);\r
- $count[$period]['percent'] = empty($values['maxscore']) ? $blank : round(100 * $values['score'] / $values['maxscore'], 0);\r
- // blank out zero click values\r
- if ($period=='click') {\r
- foreach ($values as $detail=>$value) {\r
- if ($detail=='answers' || $detail=='hints' || $detail=='clues' || $detail=='events') {\r
- if (empty($value)) {\r
- $count[$period][$detail] = $blank;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- $this->data['totals'] = array(\r
- $count['click']['answers'], // "q's tried"\r
- $count['clicks']['answers'], // "q's tried so far"\r
- $count['click']['correct'], // "right"\r
- $count['click']['wrong'], // "wrong"\r
- $count['click']['nottried'], // "not tried"\r
- $count['clicks']['correct'], // "right so far"\r
- $count['clicks']['wrong'], // "wrong so far"\r
- $count['clicks']['nottried'], // "not tried so far"\r
- $count['click']['answers'], // "answers",\r
- $count['click']['hints'], // "hints",\r
- $count['click']['clues'], // "clues",\r
- $count['click']['events'], // "answers",\r
- $count['clicks']['hints'], // "hints so far",\r
- $count['clicks']['clues'], // "clues so far",\r
- $count['click']['score'], // 'raw score',\r
- $count['click']['maxscore'], // 'max score',\r
- $count['click']['percent'], // '% score'\r
- $count['clicks']['score'], // 'raw score,\r
- $count['clicks']['maxscore'], // 'max score,\r
- $count['clicks']['percent'], // '% score\r
- $attempt->score // 'hotpot score'\r
- );\r
- }\r
- function update_event_count(&$click, $detail, $q) {\r
- if ($detail=='checks' || $detail=='hints' || $detail=='clues') {\r
- $click['types'][$detail] = true;\r
- }\r
- if ($detail=='answers' || $detail=='hints' || $detail=='clues') {\r
- $click['events'][$q] = isset($click['events'][$q]) ? $click['events'][$q]+1 : 1;\r
- }\r
- if ($detail=='answers') {\r
- $click['changes'][$q] = isset($click['changes'][$q]) ? $click['changes'][$q]+1 : 1;\r
- }\r
- }\r
- function set_data(&$cells, $zone) {\r
- foreach ($this->data[$zone] as $name=>$value) {\r
- $cells[] = $value;\r
- }\r
- }\r
-} // end class\r
-?>\r
+<?php // $Id$
+/// Overview report just displays a big table of all the attempts
+class hotpot_report extends hotpot_default_report {
+ function display(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options) {
+ global $CFG;
+ // create the tables
+ $tables = array();
+ $this->create_clickreport_table($hotpot, $cm, $course, $users, $attempts, $questions, $options, $tables);
+ // print the tables
+ $this->print_report($course, $hotpot, $tables, $options);
+ return true;
+ }
+ function create_clickreport_table(&$hotpot, &$cm, &$course, &$users, &$attempts, &$questions, &$options, &$tables) {
+ global $CFG;
+ $is_html = ($options['reportformat']=='htm');
+ // time and date format strings // date format strings
+ $strftimetime = '%H:%M:%S';
+ $strftimedate = get_string('strftimedate');
+ // get the current time and max execution time
+ $start_report_time = microtime();
+ $max_execution_time = ini_get('max_execution_time');
+ $correct = get_string('reportcorrectsymbol', 'hotpot');
+ $wrong = get_string('reportwrongsymbol', 'hotpot');
+ $nottried = get_string('reportnottriedsymbol', 'hotpot');
+ // shortcuts for font tags
+ $blank = $is_html ? ' ' : "";
+ // store question count
+ $questioncount = count($questions);
+ // array to map columns onto question ids ($col => $id)
+ $questionids = array_keys($questions);
+ // store exercise type
+ $exercisetype = $this->get_exercisetype($questions, $questionids, $blank);
+ // initialize details ('events' must go last)
+ $details = array('checks', 'status', 'answers', 'changes', 'hints', 'clues', 'events');
+ // initialize $table
+ unset($table);
+ $table->border = 1;
+ $table->width = '100%';
+ // initialize legend, if necessary
+ if (!empty($options['reportshowlegend'])) {
+ $table->legend = array();
+ }
+ // start $table headings
+ $this->set_head($options, $table, 'exercise');
+ $this->set_head($options, $table, 'user');
+ $this->set_head($options, $table, 'attempt');
+ $this->set_head($options, $table, 'click');
+ // store clicktype column number
+ $clicktype_col = count($table->head)-1;
+ // finish $table headings
+ $this->set_head($options, $table, 'details', $exercisetype, $details, $questioncount);
+ $this->set_head($options, $table, 'totals', $exercisetype);
+ // set align and wrap
+ $this->set_align_and_wrap($table);
+ // is link to review allowed?
+ $allow_review = ($is_html && (has_capability('mod/hotpot:viewreport',get_context_instance(CONTEXT_COURSE, $course->id)) || $hotpot->review));
+ // initialize array of data values
+ $this->data = array();
+ // set exercise data values
+ $this->set_data_exercise($cm, $course, $hotpot, $questions, $questionids, $questioncount, $blank);
+ // add details of users' responses
+ foreach ($users as $user) {
+ $this->set_data_user($options, $course, $user);
+ unset($clickreportid);
+ foreach ($user->attempts as $attempt) {
+ // initialize totals for
+ $click = array(
+ 'qnumber' => array(),
+ 'correct' => array(),
+ 'wrong' => array(),
+ 'answers' => array(),
+ 'hints' => array(),
+ 'clues' => array(),
+ 'changes' => array(),
+ 'checks' => array(),
+ 'events' => array(),
+ 'score' => array(),
+ 'weighting' => array()
+ );
+ $clicktypes = array();
+ // is the start of a new attempt?
+ // (clicks in the same attempt have the same clickreportid)
+ if (!isset($clickreportid) || $clickreportid != $attempt->clickreportid) {
+ $clickcount = 1;
+ $clickreportid = $attempt->clickreportid;
+ // initialize totals for all clicks in this attempt
+ $clicks = $click; // $click has just been initialized
+ $this->set_data_attempt($attempt, $strftimedate, $strftimetime, $blank);
+ }
+ $cells = array();
+ $this->set_data($cells, 'exercise');
+ $this->set_data($cells, 'user');
+ $this->set_data($cells, 'attempt');
+ // get responses to questions in this attempt
+ foreach ($attempt->responses as $response) {
+ // set $q(uestion number)
+ $q = array_search($response->question, $questionids);
+ $click['qnumber'][$q] = true;
+ // was this question answered correctly?
+ if ($answer = hotpot_strings($response->correct)) {
+ // mark the question as correctly answered
+ if (empty($clicks['correct'][$q])) {
+ $click['correct'][$q] = true;
+ $clicks['correct'][$q] = true;
+ }
+ // unset 'wrong' flags, if necessary
+ if (isset($click['wrong'][$q])) {
+ unset($click['wrong'][$q]);
+ }
+ if (isset($clicks['wrong'][$q])) {
+ unset($clicks['wrong'][$q]);
+ }
+ // otherwise, was the question answered wrongly?
+ } else if ($answer = hotpot_strings($response->wrong)) {
+ // mark the question as wrongly answered
+ $click['wrong'][$q] = true;
+ $clicks['wrong'][$q] = true;
+ } else { // not correct or wrong (curious?!)
+ unset($answer);
+ }
+ if (!empty($click['correct'][$q]) || !empty($click['wrong'][$q])) {
+ $click['score'][$q] = $response->score;
+ $clicks['score'][$q] = $response->score;
+ $weighting = isset($response->weighting) ? $response->weighting : 100;
+ $click['weighting'][$q] = $weighting;
+ $clicks['weighting'][$q] =$weighting;
+ }
+ foreach($details as $detail) {
+ switch ($detail) {
+ case 'answers':
+ if (isset($answer) && is_string($answer) && !empty($answer)) {
+ $click[$detail][$q] = $answer;
+ }
+ break;
+ case 'hints':
+ case 'clues':
+ case 'checks':
+ if (isset($response->$detail) && is_numeric($response->$detail) && $response->$detail>0) {
+ if (!isset($click[$detail][$q]) || $click[$detail][$q] < $response->$detail) {
+ $click[$detail][$q] = $response->$detail;
+ }
+ }
+ break;
+ }
+ } // end foreach $detail
+ } // end foreach $response
+ $click['types'] = array();
+ $this->data['details'] = array();
+ foreach($details as $detail) {
+ for ($q=0; $q<$questioncount; $q++) {
+ switch ($detail) {
+ case 'status':
+ if (isset($clicks['correct'][$q])) {
+ $this->data['details'][] = $correct;
+ } else if (isset($clicks['wrong'][$q])) {
+ $this->data['details'][] = $wrong;
+ } else if (isset($click['qnumber'][$q])) {
+ $this->data['details'][] = $nottried;
+ } else { // this question did not appear in this attempt
+ $this->data['details'][] = $blank;
+ }
+ break;
+ case 'answers':
+ case 'hints':
+ case 'clues':
+ case 'checks':
+ if (!isset($clicks[$detail][$q])) {
+ if (!isset($click[$detail][$q])) {
+ $this->data['details'][] = $blank;
+ } else {
+ $clicks[$detail][$q] = $click[$detail][$q];
+ if ($detail=='answers') {
+ $this->set_legend($table, $q, $click[$detail][$q], $questions[$questionids[$q]]);
+ }
+ $this->data['details'][] = $click[$detail][$q];
+ $this->update_event_count($click, $detail, $q);
+ }
+ } else {
+ if (!isset($click[$detail][$q])) {
+ $this->data['details'][] = $blank;
+ } else {
+ $difference = '';
+ if ($detail=='answers') {
+ if ($click[$detail][$q] != $clicks[$detail][$q]) {
+ $pattern = '/^'.preg_quote($clicks[$detail][$q], '/').',/';
+ $difference = preg_replace($pattern, '', $click[$detail][$q], 1);
+ }
+ } else { // hints, clues, checks
+ if ($click[$detail][$q] > $clicks[$detail][$q]) {
+ $difference = $click[$detail][$q] - $clicks[$detail][$q];
+ }
+ }
+ if ($difference) {
+ $clicks[$detail][$q] = $click[$detail][$q];
+ $click[$detail][$q] = $difference;
+ if ($detail=='answers') {
+ $this->set_legend($table, $q, $difference, $questions[$questionids[$q]]);
+ }
+ $this->data['details'][] = $difference;
+ $this->update_event_count($click, $detail, $q);
+ } else {
+ unset($click[$detail][$q]);
+ $this->data['details'][] = $blank;
+ }
+ }
+ }
+ break;
+ case 'changes':
+ case 'events':
+ if (empty($click[$detail][$q])) {
+ $this->data['details'][] = $blank;
+ } else {
+ $this->data['details'][] = $click[$detail][$q];
+ }
+ break;
+ default:
+ // do nothing
+ break;
+ } // end switch
+ } // for $q
+ } // foreach $detail
+ // set data cell values for
+ $this->set_data_click(
+ $allow_review ? '<a href="review.php?hp='.$hotpot->id.'&attempt='.$attempt->id.'">'.$clickcount.'</a>' : $clickcount,
+ trim(userdate($attempt->timefinish, $strftimetime)),
+ $exercisetype,
+ $click
+ );
+ $this->set_data($cells, 'click');
+ $this->set_data($cells, 'details');
+ $this->set_data_totals($click, $clicks, $questioncount, $blank, $attempt);
+ $this->set_data($cells, 'totals');
+ $table->data[] = $cells;
+ $clickcount++;
+ } // end foreach $attempt
+ // insert 'tabledivider' between users
+ $table->data[] = 'hr';
+ } // end foreach $user
+ // remove final 'hr' from data rows
+ array_pop($table->data);
+ if ($is_html && $CFG->hotpot_showtimes) {
+ $count = count($users);
+ $duration = sprintf("%0.3f", microtime_diff($start_report_time, microtime()));
+ print "$count users processed in $duration seconds (".sprintf("%0.3f", $duration/$count).' secs/user)<hr size="1" noshade="noshade" />'."\n";
+ }
+ $tables[] = &$table;
+ $this->create_legend_table($tables, $table);
+ } // end function
+ function get_exercisetype(&$questions, &$questionids, &$blank) {
+ if (empty($questions)) {
+ $type = $blank;
+ } else {
+ switch ($questions[$questionids[0]]->type) {
+ case HOTPOT_JCB:
+ $type = "JCB";
+ break;
+ case HOTPOT_JCLOZE :
+ $type = "JCloze";
+ break;
+ case HOTPOT_JCROSS :
+ $type = "JCross";
+ break;
+ case HOTPOT_JMATCH :
+ $type = "JMatch";
+ break;
+ case HOTPOT_JMIX :
+ $type = "JMix";
+ break;
+ case HOTPOT_JQUIZ :
+ $type = "JQuiz";
+ break;
+ case HOTPOT_TEXTOYS_RHUBARB :
+ $type = "Rhubarb";
+ break;
+ case HOTPOT_TEXTOYS_SEQUITUR :
+ $type = "Sequitur";
+ break;
+ default:
+ $type = $blank;
+ }
+ }
+ return $type;
+ }
+ function set_head(&$options, &$table, $zone, $exercisetype='', $details=array(), $questioncount=0) {
+ if (empty($table->head)) {
+ $table->head = array();
+ }
+ switch ($zone) {
+ case 'exercise':
+ array_push($table->head,
+ get_string('reportcoursename', 'hotpot'),
+ get_string('reportsectionnumber', 'hotpot'),
+ get_string('reportexercisenumber', 'hotpot'),
+ get_string('reportexercisename', 'hotpot'),
+ get_string('reportexercisetype', 'hotpot'),
+ get_string('reportnumberofquestions', 'hotpot')
+ );
+ break;
+ case 'user':
+ array_push($table->head,
+ get_string('reportstudentid', 'hotpot'),
+ get_string('reportlogindate', 'hotpot'),
+ get_string('reportlogintime', 'hotpot'),
+ get_string('reportlogofftime', 'hotpot')
+ );
+ break;
+ case 'attempt':
+ array_push($table->head,
+ get_string('reportattemptnumber', 'hotpot'),
+ get_string('reportattemptstart', 'hotpot'),
+ get_string('reportattemptfinish', 'hotpot')
+ );
+ break;
+ case 'click':
+ array_push($table->head,
+ get_string('reportclicknumber', 'hotpot'),
+ get_string('reportclicktime', 'hotpot'),
+ get_string('reportclicktype', 'hotpot')
+ );
+ break;
+ case 'details':
+ foreach($details as $detail) {
+ if ($exercisetype=='JQuiz' && $detail=='clues') {
+ $detail = 'showanswer';
+ }
+ $detail = get_string("report$detail", 'hotpot');
+ for ($i=0; $i<$questioncount; $i++) {
+ $str = get_string('questionshort', 'hotpot', $i+1);
+ if ($i==0 || $options['reportformat']!='htm') {
+ $str = "$detail $str";
+ }
+ $table->head[] = $str;
+ }
+ }
+ break;
+ case 'totals':
+ $reportpercentscore =get_string('reportpercentscore', 'hotpot');
+ if (!function_exists('clean_getstring_data')) { // Moodle 1.4 (and less)
+ $reportpercentscore = str_replace('%', '%%', $reportpercentscore);
+ }
+ array_push($table->head,
+ get_string('reportthisclick', 'hotpot', get_string('reportquestionstried', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reportquestionstried', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportright', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportwrong', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportnottried', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reportright', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reportwrong', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reportnottried', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportanswers', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reporthints', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportevents', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reporthints', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string($exercisetype=='JQuiz' ? 'reportshowanswer' : 'reportclues', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportrawscore', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', get_string('reportmaxscore', 'hotpot')),
+ get_string('reportthisclick', 'hotpot', $reportpercentscore),
+ get_string('reportsofar', 'hotpot', get_string('reportrawscore', 'hotpot')),
+ get_string('reportsofar', 'hotpot', get_string('reportmaxscore', 'hotpot')),
+ get_string('reportsofar', 'hotpot', $reportpercentscore),
+ get_string('reporthotpotscore', 'hotpot')
+ );
+ break;
+ } // end switch
+ }
+ function set_align_and_wrap(&$table) {
+ $count = count($table->head);
+ for ($i=0; $i<$count; $i++) {
+ if ($i==0 || $i==1 || $i==2 || $i==4 || $i==5 || $i>=7) {
+ // numeric (and short text) columns
+ $table->align[] = 'center';
+ $table->wrap[] = '';
+ } else {
+ // text columns
+ $table->align[] = 'left';
+ $table->wrap[] = 'nowrap';
+ }
+ }
+ }
+ function set_data_exercise(&$cm, &$course, &$hotpot, &$questions, &$questionids, &$questioncount, &$blank) {
+ // get exercise details (course name, section number, activity number, quiztype and question count)
+ $record = get_record("course_sections", "id", $cm->section);
+ $this->data['exercise'] = array(
+ 'course' => $course->shortname,
+ 'section' => empty($record) ? $blank : $record->section+1,
+ 'number' => empty($record) ? $blank : array_search($cm->id, explode(',', $record->sequence))+1,
+ 'name' => $hotpot->name,
+ 'type' => $this->get_exercisetype($questions, $questionids, $blank),
+ 'questioncount' => $questioncount
+ );
+ }
+ function set_data_user(&$options, &$course, &$user) {
+ global $CFG;
+ // shortcut to first attempt record (which also hold user info)
+ $attempt = &$user->attempts[0];
+ $idnumber = $attempt->idnumber;
+ if (empty($idnumber)) {
+ $idnumber = fullname($attempt);
+ }
+ if ($options['reportformat']=='htm') {
+ $idnumber = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.$idnumber.'</a>';
+ }
+ $this->data['user'] = array(
+ 'idnumber' => $idnumber,
+ );
+ }
+ function set_data_attempt(&$attempt, &$strftimedate, &$strftimetime, &$blank) {
+ global $CFG;
+ $records = get_records_sql_menu("
+ SELECT userid, MAX(time) AS logintime
+ FROM {$CFG->prefix}log
+ WHERE userid=$attempt->userid AND action='login' AND time<$attempt->timestart
+ GROUP BY userid
+ ");
+ if (empty($records)) {
+ $logindate = $blank;
+ $logintime = $blank;
+ } else {
+ $logintime = $records[$attempt->userid];
+ $logindate = trim(userdate($logintime, $strftimedate));
+ $logintime = trim(userdate($logintime, $strftimetime));
+ }
+ $records = get_records_sql_menu("
+ SELECT userid, MIN(time) AS logouttime
+ FROM {$CFG->prefix}log
+ WHERE userid=$attempt->userid AND action='logout' AND time>$attempt->cr_timefinish
+ GROUP BY userid
+ ");
+ 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
+?>
-<?PHP \r
-\r
-class hotpot_xml_quiz_template extends hotpot_xml_template_default {\r
-\r
- // constructor function for this class\r
- function hotpot_xml_quiz_template(&$parent) {\r
-\r
- $this->parent = &$parent;\r
- \r
- $get_js = optional_param('js', false);\r
- $get_css = optional_param('css', false);\r
-\r
- if (!empty($get_css)) {\r
- // set $this->css\r
- $this->v6_expand_StyleSheet(); \r
-\r
- } else if (!empty($get_js)) {\r
- // set $this->js\r
- $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js');\r
-\r
- } else {\r
- // set $this->html\r
- $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html');\r
- }\r
-\r
- // expand special strings, if any\r
- $pattern = '';\r
- switch ($this->parent->quiztype) {\r
- case 'jcloze':\r
- $pattern = '/\[(PreloadImageList)\]/';\r
- break;\r
- case 'jcross':\r
- $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/';\r
- break;\r
- case 'jmatch':\r
- $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/';\r
- break;\r
- case 'jmix':\r
- $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/';\r
- break;\r
- case 'jquiz':\r
- $pattern = '/\[(PreloadImageList|QsToShow)\]/';\r
- break;\r
- }\r
- if (!empty($pattern)) {\r
- $this->expand_strings('html', $pattern);\r
- }\r
- }\r
-\r
- // captions and messages\r
-\r
- function v6_expand_AlsoCorrect() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');\r
- }\r
- function v6_expand_CapitalizeFirst() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter');\r
- }\r
- function v6_expand_CheckCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,check-caption');\r
- }\r
- function v6_expand_CorrectIndicator() {\r
- return $this->js_value('hotpot-config-file,global,correct-indicator');\r
- }\r
- function v6_expand_Back() {\r
- return $this->int_value('hotpot-config-file,global,include-back');\r
- }\r
- function v6_expand_BackCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,back-caption');\r
- }\r
- function v6_expand_ClickToAdd() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add');\r
- }\r
- function v6_expand_ClueCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,clue-caption');\r
- }\r
- function v6_expand_Clues() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues');\r
- }\r
- function v6_expand_Contents() {\r
- return $this->int_value('hotpot-config-file,global,include-contents');\r
- }\r
- function v6_expand_ContentsCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,contents-caption');\r
- }\r
- function v6_expand_GuessCorrect() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct');\r
- }\r
- function v6_expand_GuessIncorrect() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect');\r
- }\r
- function v6_expand_Hint() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint');\r
- }\r
- function v6_expand_HintCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,hint-caption');\r
- }\r
- function v6_expand_IncorrectIndicator() {\r
- return $this->js_value('hotpot-config-file,global,incorrect-indicator');\r
- }\r
- function v6_expand_LastQCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,last-q-caption');\r
- }\r
- function v6_expand_NextCorrect() {\r
- $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part');\r
- if (empty($value)) { // jquiz\r
- $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');\r
- }\r
- return $value;\r
- }\r
- function v6_expand_NextEx() {\r
- return $this->int_value('hotpot-config-file,global,include-next-ex');\r
- }\r
- function v6_expand_NextExCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,next-ex-caption');\r
- }\r
- function v6_expand_NextQCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,next-q-caption');\r
- }\r
- function v6_expand_OKCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,ok-caption');\r
- }\r
- function v6_expand_Restart() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart');\r
- }\r
- function v6_expand_RestartCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,restart-caption');\r
- }\r
- function v6_expand_ShowAllQuestionsCaption() {\r
- return $this->js_value('hotpot-config-file,global,show-all-questions-caption');\r
- }\r
- function v6_expand_ShowOneByOneCaption() {\r
- return $this->js_value('hotpot-config-file,global,show-one-by-one-caption');\r
- }\r
- function v6_expand_TheseAnswersToo() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');\r
- }\r
- function v6_expand_ThisMuch() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct');\r
- }\r
- function v6_expand_Undo() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo');\r
- }\r
- function v6_expand_UndoCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,global,undo-caption');\r
- }\r
- function v6_expand_YourScoreIs() {\r
- return $this->js_value('hotpot-config-file,global,your-score-is');\r
- }\r
-\r
- // reading\r
-\r
- function v6_expand_Reading() {\r
- return $this->int_value('data,reading,include-reading');\r
- }\r
- function v6_expand_ReadingText() {\r
- $title = $this->v6_expand_ReadingTitle();\r
- $value = $this->parent->xml_value('data,reading,reading-text');\r
- $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>');\r
- return $title.$value;\r
- }\r
- function v6_expand_ReadingTitle() {\r
- $value = $this->parent->xml_value('data,reading,reading-title');\r
- return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>');\r
- }\r
-\r
- // timer \r
-\r
- function v6_expand_Timer() {\r
- return $this->int_value('data,timer,include-timer');\r
- }\r
- function v6_expand_JSTimer() {\r
- return $this->read_template('hp6timer.js_');\r
- }\r
- function v6_expand_Seconds() {\r
- return $this->parent->xml_value('data,timer,seconds');\r
- }\r
-\r
- // send results \r
-\r
- function v6_expand_SendResults() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email');\r
- }\r
- function v6_expand_JSSendResults() {\r
- return $this->read_template('hp6sendresults.js_');\r
- }\r
- function v6_expand_FormMailURL() {\r
- return $this->parent->xml_value('hotpot-config-file,global,formmail-url');\r
- }\r
- function v6_expand_EMail() {\r
- return $this->parent->xml_value('hotpot-config-file,global,email');\r
- }\r
- function v6_expand_NamePlease() {\r
- return $this->js_value('hotpot-config-file,global,name-please');\r
- }\r
-\r
- // preload images\r
-\r
- function v6_expand_PreloadImages() {\r
- $value = $this->v6_expand_PreloadImageList();\r
- return empty($value) ? false : true;\r
- }\r
- function v6_expand_PreloadImageList() {\r
-\r
- // check it has not been set already\r
- if (!isset($this->PreloadImageList)) {\r
-\r
- // the list of image urls\r
- $list = array();\r
-\r
- // extract <img> tags\r
- $img_tag = htmlspecialchars('|<img.*?src="(.*?)".*?>|is');\r
- if (preg_match_all($img_tag, $this->parent->source, $matches)) {\r
- $list = $matches[1];\r
-\r
- // remove duplicates\r
- $list = array_unique($list);\r
- }\r
-\r
- // convert to comma delimited string\r
- $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'";\r
- }\r
- return $this->PreloadImageList;\r
- }\r
-\r
- // html files (all quiz types)\r
-\r
- function v6_expand_PlainTitle() {\r
- return $this->parent->xml_value('data,title');\r
- }\r
- function v6_expand_ExerciseSubtitle() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle');\r
- }\r
- function v6_expand_Instructions() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions');\r
- }\r
- function v6_expand_DublinCoreMetadata() {\r
- $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n";\r
- if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) {\r
- // do nothing (there is no more dc info)\r
- } else {\r
- $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n";\r
- $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n";\r
- }\r
- return $dc;\r
- }\r
- function v6_expand_FullVersionInfo() {\r
- global $CFG;\r
- require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module\r
- return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')';\r
- }\r
- function v6_expand_HeaderCode() {\r
- return $this->parent->xml_value('hotpot-config-file,global,header-code');\r
- }\r
- function v6_expand_StyleSheet() {\r
- $this->read_template('hp6.cs_', 'css');\r
- $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css);\r
- return $this->css;\r
- }\r
-\r
- // stylesheet (hp6.cs_)\r
-\r
- function v6_expand_PageBGColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');\r
- }\r
- function v6_expand_GraphicURL() {\r
- return $this->parent->xml_value('hotpot-config-file,global,graphic-url');\r
- }\r
- function v6_expand_ExBGColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
- }\r
-\r
- function v6_expand_FontFace() {\r
- return $this->parent->xml_value('hotpot-config-file,global,font-face');\r
- }\r
- function v6_expand_FontSize() {\r
- return $this->parent->xml_value('hotpot-config-file,global,font-size');\r
- }\r
- function v6_expand_TextColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,text-color');\r
- }\r
- function v6_expand_TitleColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,title-color');\r
- }\r
- function v6_expand_LinkColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,link-color');\r
- }\r
- function v6_expand_VLinkColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,vlink-color');\r
- }\r
-\r
- function v6_expand_NavTextColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');\r
- }\r
- function v6_expand_NavBarColor() {\r
- return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
- }\r
- function v6_expand_NavLightColor() {\r
- $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
- return $this->get_halfway_color($color, '#ffffff'); \r
- }\r
- function v6_expand_NavShadeColor() {\r
- $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');\r
- return $this->get_halfway_color($color, '#000000');\r
- }\r
-\r
- function v6_expand_FuncLightColor() { // top-left of buttons\r
- $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
- return $this->get_halfway_color($color, '#ffffff');\r
- }\r
- function v6_expand_FuncShadeColor() { // bottom right of buttons\r
- $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');\r
- return $this->get_halfway_color($color, '#000000');\r
- }\r
-\r
- // navigation buttons\r
-\r
- function v6_expand_NavButtons() {\r
- $back = $this->v6_expand_Back();\r
- $next_ex = $this->v6_expand_NextEx();\r
- $contents = $this->v6_expand_Contents();\r
- return (empty($back) && empty($next_ex) && empty($contents) ? false : true);\r
- }\r
- function v6_expand_NavBarJS() {\r
- return $this->v6_expand_NavButtons();\r
- }\r
-\r
- // js files (all quiz types)\r
-\r
- function v6_expand_JSBrowserCheck() {\r
- return $this->read_template('hp6browsercheck.js_');\r
- }\r
- function v6_expand_JSButtons() {\r
- return $this->read_template('hp6buttons.js_');\r
- }\r
- function v6_expand_JSCard() {\r
- return $this->read_template('hp6card.js_');\r
- }\r
- function v6_expand_JSCheckShortAnswer() {\r
- return $this->read_template('hp6checkshortanswer.js_');\r
- }\r
- function v6_expand_JSHotPotNet() {\r
- return $this->read_template('hp6hotpotnet.js_');\r
- }\r
- function v6_expand_JSShowMessage() {\r
- return $this->read_template('hp6showmessage.js_');\r
- }\r
- function v6_expand_JSUtilities() {\r
- return $this->read_template('hp6utilities.js_');\r
- }\r
-\r
- // js files\r
-\r
- function v6_expand_JSJCloze6() {\r
- return $this->read_template('jcloze6.js_');\r
- }\r
- function v6_expand_JSJCross6() {\r
- return $this->read_template('jcross6.js_');\r
- }\r
- function v6_expand_JSJMatch6() {\r
- return $this->read_template('jmatch6.js_');\r
- }\r
- function v6_expand_JSJMix6() {\r
- return $this->read_template('jmix6.js_');\r
- }\r
- function v6_expand_JSJQuiz6() {\r
- return $this->read_template('jquiz6.js_');\r
- }\r
-\r
- // drag and drop\r
-\r
- function v6_expand_JSDJMatch6() {\r
- return $this->read_template('djmatch6.js_');\r
- }\r
- function v6_expand_JSDJMix6() {\r
- return $this->read_template('djmix6.js_');\r
- }\r
-\r
- // what are these for?\r
-\r
- function v6_expand_JSFJMatch6() {\r
- return $this->read_template('fjmatch6.js_');\r
- }\r
- function v6_expand_JSFJMix6() {\r
- return $this->read_template('fjmix6.js_');\r
- }\r
-\r
- // jmatch6.js_\r
-\r
- function v6_expand_ShuffleQs() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions');\r
- }\r
- function v6_expand_QsToShow() {\r
- $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions');\r
- if ($i) {\r
- $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show');\r
- }\r
- if (empty($i)) {\r
- $i = 0;\r
- switch ($this->parent->quiztype) {\r
- case 'jmatch':\r
- $values = $this->parent->xml_values('data,matching-exercise,pair');\r
- $i = count($values);\r
- break;\r
- case 'jquiz':\r
- while ($this->parent->xml_value('data,questions,question-record', "[$i]['#']['question'][0]['#']")) {\r
- $i++;\r
- }\r
- break;\r
- } // end switch\r
- }\r
- return $i;\r
- }\r
- function v6_expand_MatchDivItems() {\r
- $l_items = array();\r
- $r_items = array();\r
- $this->get_jmatch_items($l_items, $r_items);\r
-\r
- $l_keys = $this->shuffle_jmatch_items($l_items);\r
- $r_keys = $this->shuffle_jmatch_items($r_items);\r
-\r
- $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>';\r
- foreach ($r_keys as $key) {\r
- $options .= '<option value="'.$key.'">'.$r_items[$key]['text'][0]['#'].'</option>'."\n";\r
- }\r
-\r
- $str = '';\r
- foreach ($l_keys as $key) {\r
- $str .= '<tr><td class="LeftItem">'.$l_items[$key]['text'][0]['#'].'</td>';\r
- $str .= '<td class="RightItem"><select id="s'.$key.'_'.$key.'">'.$options.'</select></td>';\r
- $str .= '<td></td></tr>';\r
- }\r
- return $str;\r
- }\r
-\r
- // jmix6.js_\r
-\r
- function v6_expand_Punctuation() {\r
- $tags = 'data,jumbled-order-exercise';\r
- $chars = array_merge(\r
- $this->jmix_Punctuation("$tags,main-order,segment"),\r
- $this->jmix_Punctuation("$tags,alternate")\r
- );\r
- $chars = array_unique($chars);\r
- $chars = implode('', $chars);\r
- $chars = $this->js_safe($chars, true);\r
- return $chars;\r
- }\r
- function jmix_Punctuation($tags) {\r
- $chars = array();\r
-\r
- // all punctutation except '&#;' (because they are used in html entities)\r
- $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~');\r
- $pattern = "/&#x([0-9A-F]+);/i";\r
- $i = 0;\r
-\r
- // get next segment (or alternate answer)\r
- while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
-\r
- // convert low-ascii punctuation to entities\r
- $value = strtr($value, $ENTITIES);\r
-\r
- // extract all hex HTML entities\r
- if (preg_match_all($pattern, $value, $matches)) {\r
-\r
- // loop through hex entities\r
- $m_max = count($matches[0]);\r
- for ($m=0; $m<$m_max; $m++) {\r
-\r
- // convert to hex number\r
- eval('$hex=0x'.$matches[1][$m].';');\r
-\r
- // is this a punctuation character?\r
- if (\r
- ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation\r
- ($hex>=0x2000 && $hex<=0x206F) || // general punctuation\r
- ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation\r
- ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability\r
- ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants\r
- ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1)\r
- ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2)\r
- ($hex>=0xFFE0 && $hex<=0xFFEE) // halfwidth and fullwidth forms (3)\r
- ) {\r
- // add this character\r
- $chars[] = $matches[0][$m];\r
- }\r
- }\r
- }\r
- $i++;\r
- }\r
-\r
- return $chars;\r
- }\r
- function v6_expand_OpenPunctuation() {\r
- $tags = 'data,jumbled-order-exercise';\r
- $chars = array_merge(\r
- $this->jmix_OpenPunctuation("$tags,main-order,segment"),\r
- $this->jmix_OpenPunctuation("$tags,alternate")\r
- );\r
- $chars = array_unique($chars);\r
- $chars = implode('', $chars);\r
- $chars = $this->js_safe($chars, true);\r
- return $chars;\r
- }\r
- function jmix_OpenPunctuation($tags) {\r
- $chars = array();\r
-\r
- // unicode punctuation designations (pi="initial quote", ps="open")\r
- // http://www.sql-und-xml.de/unicode-database/pi.html\r
- // http://www.sql-und-xml.de/unicode-database/ps.html\r
- $pi = '0022|0027|00AB|2018|201B|201C|201F|2039';\r
- $ps = '0028|005B|007B|0F3A|0F3C|169B|201A|201E|2045|207D|208D|2329|23B4|2768|276A|276C|276E|2770|2772|2774|27E6|27E8|27EA|2983|2985|2987|2989|298B|298D|298F|2991|2993|2995|2997|29D8|29DA|29FC|3008|300A|300C|300E|3010|3014|3016|3018|301A|301D|FD3E|FE35|FE37|FE39|FE3B|FE3D|FE3F|FE41|FE43|FE47|FE59|FE5B|FE5D|FF08|FF3B|FF5B|FF5F|FF62';\r
- $pattern = "/(&#x($pi|$ps);)/i";\r
-\r
- $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{');\r
-\r
- $i = 0;\r
- while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
- $value = strtr($value, $ENTITIES);\r
- if (preg_match_all($pattern, $value, $matches)) {\r
- $chars = array_merge($chars, $matches[0]);\r
- } \r
- $i++;\r
- }\r
-\r
- return $chars;\r
- }\r
- function jmix_encode_punctuation($str) {\r
- $ENTITIES = array();\r
- $i_max = strlen($str);\r
- for ($i=0; $i<$i_max; $i++) {\r
- $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';';\r
- }\r
- return $ENTITIES;\r
- }\r
- function v6_expand_ExerciseTitle() {\r
- return $this->parent->xml_value('data,title');\r
- }\r
-\r
- // Jmix specials\r
-\r
- function v6_expand_SegmentArray() {\r
-\r
- $segments = array();\r
- $values = array();\r
- $VALUES = array();\r
-\r
- // XML tags to the start of a segment\r
- $tags = 'data,jumbled-order-exercise,main-order,segment';\r
-\r
- $i = 0;\r
- while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
- $VALUE = strtoupper($value);\r
- $key = array_search($VALUE, $VALUES);\r
- if (is_numeric($key)) {\r
- $segments[] = $key;\r
- } else {\r
- $segments[] = $i;\r
- $values[$i] = $value;\r
- $VALUES[$i] = $VALUE;\r
- }\r
- $i++;\r
- }\r
-\r
- $this->seed_random_number_generator();\r
- $keys = array_keys($segments);\r
- shuffle($keys);\r
-\r
- $str = '';\r
- for($i=0; $i<count($keys); $i++) {\r
- $key = $segments[$keys[$i]];\r
- $str .= "Segments[$i] = new Array();\n";\r
- $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n";\r
- $str .= "Segments[$i][1] = ".($key+1).";\n";\r
- $str .= "Segments[$i][2] = 0;\n";\r
- }\r
- return $str;\r
- }\r
- function v6_expand_AnswerArray() {\r
-\r
- $segments = array();\r
- $values = array();\r
- $VALUES = array();\r
- $escapedvalues = array();\r
-\r
- // XML tags to the start of a segment\r
- $tags = 'data,jumbled-order-exercise,main-order,segment';\r
-\r
- $i = 0;\r
- while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
- $VALUE = strtoupper($value);\r
- $key = array_search($VALUE, $VALUES);\r
- if (is_numeric($key)) {\r
- $segments[] = $key+1;\r
- } else {\r
- $segments[] = $i+1;\r
- $values[$i] = $value;\r
- $VALUES[$i] = $VALUE;\r
- $escapedvalues[] = preg_quote($value, '/');\r
- }\r
- $i++;\r
- }\r
-\r
- // start the answers array\r
- $a = 0;\r
- $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";\r
-\r
- // pattern to match the next part of an alternate answer\r
- $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i';\r
-\r
- // XML tags to the start of an alternate answer\r
- $tags = 'data,jumbled-order-exercise,alternate';\r
-\r
- $i = 0;\r
- while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {\r
- $segments = array();\r
- while (strlen($value) && preg_match($pattern, $value, $matches)) {\r
- $key = array_search($matches[1], $values);\r
- if (is_numeric($key)) {\r
- $segments[] = $key+1;\r
- $value = substr($value, strlen($matches[0]));\r
- } else {\r
- // invalid alternate sequence\r
- $segments = array();\r
- break;\r
- }\r
- }\r
- if (count($segments)) {\r
- $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";\r
- }\r
- $i++;\r
- }\r
- return $str;\r
- }\r
-\r
- // ===============================================================\r
-\r
- // JMix (jmix6.js_)\r
-\r
- function v6_expand_RemainingWords() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words');\r
- }\r
- function v6_expand_TimesUp() {\r
- return $this->parent->xml_value('hotpot-config-file,global,times-up');\r
- }\r
-\r
- // nav bar\r
-\r
- function v6_expand_NavBar($navbarid='') {\r
- $this->navbarid = $navbarid;\r
-\r
- $tag = 'navbar';\r
- $this->read_template('hp6navbar.ht_', $tag);\r
-\r
- unset($this->navbarid);\r
-\r
- return $this->$tag;\r
- }\r
- function v6_expand_TopNavBar() {\r
- return $this->v6_expand_NavBar('TopNavBar');\r
- }\r
- function v6_expand_BottomNavBar() {\r
- return $this->v6_expand_NavBar('BottomNavBar');\r
- }\r
-\r
- // hp6navbar.ht_\r
-\r
- function v6_expand_NavBarID() {\r
- // $this->navbarid is set in "$this->v6_expand_NavBar"\r
- return empty($this->navbarid) ? '' : $this->navbarid;\r
- }\r
- function v6_expand_ContentsURL() {\r
- $url = $this->parent->xml_value('hotpot-config-file,global,contents-url');\r
- if ($url) {\r
- $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);\r
- }\r
- return $url;\r
- }\r
- function v6_expand_NextExURL() {\r
- $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url');\r
- if ($url) {\r
- $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);\r
- }\r
- return $url;\r
- }\r
-\r
- // conditional blocks\r
-\r
- function v6_expand_ShowAnswer() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer');\r
- }\r
- function v6_expand_Slide() {\r
- return true; // whats's this (JMatch drag and drop)\r
- }\r
-\r
- // specials (JMatch)\r
-\r
- function v6_expand_FixedArray() {\r
- $l_items = array();\r
- $r_items = array();\r
- $this->get_jmatch_items($l_items, $r_items);\r
-\r
- $str = '';\r
- foreach ($l_items as $i=>$item) {\r
- $str .= "F[$i] = new Array();\n";\r
- $str .= "F[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";\r
- $str .= "F[$i][1] = ".($i+1).";\n";\r
- }\r
- return $str;\r
- }\r
- function v6_expand_DragArray() {\r
- $l_items = array();\r
- $r_items = array();\r
- $this->get_jmatch_items($l_items, $r_items);\r
-\r
- $str = '';\r
- foreach ($r_items as $i=>$item) {\r
- $str .= "D[$i] = new Array();\n";\r
- $str .= "D[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";\r
- $str .= "D[$i][1] = ".($i+1).";\n";\r
- $str .= "D[$i][2] = 0;\n";\r
- }\r
- return $str;\r
- }\r
-\r
- function get_jmatch_items(&$l_items, &$r_items) {\r
- $tags = 'data,matching-exercise,pair';\r
- $i = 0;\r
- while($item = $this->parent->xml_value($tags,"[$i]['#']['left-item'][0]['#']")) {\r
- if (!empty($item['text'][0]['#'])) {\r
- $l_items[] = $item;\r
- }\r
- $i++;\r
- }\r
- $i = 0;\r
- while($item = $this->parent->xml_value($tags,"[$i]['#']['right-item'][0]['#']")) {\r
- if (!empty($item['text'][0]['#'])) {\r
- $r_items[] = $item;\r
- }\r
- $i++;\r
- }\r
- }\r
- function shuffle_jmatch_items(&$items) {\r
- // get moveable items\r
- $moveable_keys = array();\r
- for($i=0; $i<count($items); $i++) {\r
- if(empty($items[$i]['fixed'][0]['#'])) {\r
- $moveable_keys[] = $i;\r
- }\r
- }\r
- // shuffle moveable items\r
- $this->seed_random_number_generator();\r
- shuffle($moveable_keys);\r
-\r
- $keys = array();\r
- for($i=0, $ii=0; $i<count($items); $i++) {\r
- if(empty($items[$i]['fixed'][0]['#'])) {\r
- // moveable items are inserted in a shuffled order\r
- $keys[] = $moveable_keys[$ii++];\r
- } else {\r
- // fixed items stay where they are\r
- $keys[] = $i;\r
- }\r
- }\r
- return $keys;\r
- }\r
- function seed_random_number_generator() {\r
- static $seeded_RNG = FALSE;\r
- if (!$seeded_RNG) {\r
- srand((double) microtime() * 1000000);\r
- $seeded_RNG = TRUE;\r
- }\r
- }\r
-\r
- // specials (JMix)\r
-\r
-\r
- // specials (JCloze)\r
-\r
- function v6_expand_ItemArray() {\r
- $q = 0;\r
- $str = '';\r
- switch ($this->parent->quiztype) {\r
- case 'jcloze':\r
- $tags = 'data,gap-fill,question-record';\r
- while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
- $a = 0;\r
- $aa = 0;\r
- while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
- $text = $this->js_value($tags, $answer."['text'][0]['#']", true);\r
- if (strlen($text)) {\r
- if ($aa==0) { // first time only\r
- $str .= "\n";\r
- $str .= "I[$q] = new Array();\n";\r
- $str .= "I[$q][1] = new Array();\n";\r
- }\r
- $str .= "I[$q][1][$aa] = new Array();\n";\r
- $str .= "I[$q][1][$aa][0] = '$text';\n";\r
- $aa++;\r
- }\r
- $a++;\r
- }\r
- // add clue, if any answers were found\r
- if ($aa) {\r
- $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);\r
- $str .= "I[$q][2] = '$clue';\n";\r
- }\r
- $q++;\r
- }\r
- break;\r
- case 'jquiz':\r
- $str .= "I=new Array();\n";\r
- $tags = 'data,questions,question-record';\r
- while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
- $question_type = $this->int_value($tags, $question."['question-type'][0]['#']");\r
- $weighting = $this->int_value($tags, $question."['weighting'][0]['#']");\r
- $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);\r
-\r
- $answers = $question."['answers'][0]['#']";\r
-\r
- $a = 0;\r
- $aa = 0;\r
- while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
- $text = $this->js_value($tags, $answer."['text'][0]['#']", true);\r
- $feedback = $this->js_value($tags, $answer."['feedback'][0]['#']", true);\r
- $correct = $this->int_value($tags, $answer."['correct'][0]['#']");\r
- $percent = $this->int_value($tags, $answer."['percent-correct'][0]['#']");\r
- $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");\r
- if (strlen($text)) {\r
- if ($aa==0) { // first time only\r
- $str .= "\n";\r
- $str .= "I[$q] = new Array();\n";\r
- $str .= "I[$q][0] = $weighting;\n";\r
- $str .= "I[$q][1] = '$clue';\n";\r
- $str .= "I[$q][2] = '".($question_type-1)."';\n";\r
- $str .= "I[$q][3] = new Array();\n";\r
- }\r
- $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n";\r
- $aa++;\r
- }\r
- $a++;\r
- }\r
- $q++;\r
- }\r
- break;\r
- }\r
- return $str;\r
- }\r
-\r
- function v6_expand_ClozeBody() {\r
- $str = '';\r
-\r
- // get drop down list of words, if required\r
- $dropdownlist = '';\r
- if ($this->v6_use_DropDownList()) {\r
- $this->v6_set_WordList();\r
- foreach ($this->wordlist as $word) {\r
- $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>';\r
- }\r
- }\r
-\r
- // cache clues flag and caption\r
- $includeclues = $this->v6_expand_Clues();\r
- $cluecaption = $this->v6_expand_ClueCaption();\r
-\r
- // detect if cloze starts with gap\r
- $strpos = strpos($this->parent->source, '<gap-fill><question-record>');\r
- if (is_numeric($strpos)) {\r
- $startwithgap = true;\r
- } else {\r
- $startwithgap = false;\r
- }\r
-\r
- // initialize loop values\r
- $q = 0;\r
- $tags = 'data,gap-fill';\r
- $question_record = "$tags,question-record";\r
-\r
- // loop through text and gaps\r
- do {\r
- $text = $this->parent->xml_value($tags, "[0]['#'][$q]");\r
- $gap = '';\r
- if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) {\r
- $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">';\r
- if ($this->v6_use_DropDownList()) {\r
- $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>';\r
- } else {\r
- // minimum gap size\r
- $gapsize = 6;\r
-\r
- // increase gap size to length of longest answer for this gap\r
- $a = 0;\r
- while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) {\r
- $answertext = $this->parent->xml_value($question_record, $answer."['text'][0]['#']");\r
- $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext);\r
- $gapsize = max($gapsize, strlen($answertext));\r
- $a++;\r
- }\r
-\r
- $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'"></input>';\r
- }\r
- if ($includeclues) {\r
- $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']");\r
- if (strlen($clue)) {\r
- $gap .= '<button style="line-height: 1.0" class="FuncButton" onfocus="FuncBtnOver(this)" onmouseover="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowClue('.$q.')">'.$cluecaption.'</button>';\r
- }\r
- }\r
- $gap .= '</span>';\r
- }\r
- if ($startwithgap) {\r
- $str .= "$gap$text";\r
- } else {\r
- $str .= "$text$gap";\r
- }\r
- $q++;\r
- } while (strlen($text) || strlen($gap));\r
-\r
- return $str;\r
- }\r
-\r
- // JCloze quiztype\r
-\r
- function v6_expand_WordList() {\r
- $str = '';\r
- if ($this->v6_include_WordList()) {\r
- $this->v6_set_WordList();\r
- $str = implode('    ', $this->wordlist);\r
- }\r
- return $str;\r
- }\r
- function v6_include_WordList() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list');\r
- }\r
- function v6_use_DropDownList() {\r
- return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list');\r
- }\r
- function v6_set_WordList() {\r
-\r
- if (isset($this->wordlist)) {\r
- // do nothing\r
- } else {\r
- $this->wordlist = array();\r
-\r
- // is the wordlist required\r
- if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) {\r
-\r
- $q = 0;\r
- $tags = 'data,gap-fill,question-record';\r
- while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
- $a = 0;\r
- $aa = 0;\r
- while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
- $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");\r
- $correct = $this->int_value($tags, $answer."['correct'][0]['#']");\r
- if ($text && $correct) { // $correct is always true\r
- $this->wordlist[] = $text;\r
- $aa++;\r
- }\r
- $a++;\r
- }\r
- $q++;\r
- }\r
- $this->wordlist = array_unique($this->wordlist);\r
- sort($this->wordlist);\r
- }\r
- }\r
- }\r
- function v6_expand_Keypad() {\r
- $str = '';\r
- if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) {\r
-\r
- // these characters must always be in the keypad\r
- $chars = array();\r
- $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters'));\r
-\r
- // append other characters used in the answers\r
- $tags = '';\r
- switch ($this->parent->quiztype) {\r
- case 'jcloze':\r
- $tags = 'data,gap-fill,question-record';\r
- break;\r
- case 'jquiz':\r
- $tags = 'data,questions,question-record';\r
- break;\r
- }\r
- if ($tags) {\r
- $q = 0;\r
- while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
- if ($this->parent->quiztype=='jquiz') {\r
- $answers = $question."['answers'][0]['#']";\r
- } else {\r
- $answers = $question;\r
- }\r
-\r
- $a = 0;\r
- while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
- $this->add_keypad_chars($chars, $this->parent->xml_value($tags, $answer."['text'][0]['#']"));\r
- $a++;\r
- }\r
- $q++;\r
- }\r
- }\r
-\r
- // remove duplicate characters and sort\r
- $chars = array_unique($chars);\r
- usort($chars, "hotpot_sort_keypad_chars");\r
-\r
- // create keypad buttons for each character\r
- $str .= '<div class="Keypad">';\r
- foreach ($chars as $char) {\r
- $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>";\r
- }\r
- $str .= '</div>';\r
- }\r
- return $str;\r
- }\r
- function add_keypad_chars(&$chars, $text) {\r
- if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) {\r
- $chars = array_merge($chars, $more_chars[0]);\r
- }\r
- }\r
- function v6_expand_Correct() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct');\r
- }\r
- function v6_expand_Incorrect() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect');\r
- }\r
- function v6_expand_GiveHint() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');\r
- }\r
- function v6_expand_CaseSensitive() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive');\r
- }\r
-\r
- // JCross quiztype\r
-\r
- function v6_expand_CluesAcrossLabel() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across');\r
- }\r
- function v6_expand_CluesDownLabel() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down');\r
- }\r
- function v6_expand_EnterCaption() {\r
- return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption');\r
- }\r
- function v6_expand_ShowHideClueList() {\r
- $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list');\r
- return empty($value) ? ' style="display: none;"' : '';\r
- }\r
-\r
- // JCross specials\r
-\r
- function v6_expand_CluesDown() {\r
- return $this->v6_expand_jcross_clues('D');\r
- }\r
- function v6_expand_CluesAcross() {\r
- return $this->v6_expand_jcross_clues('A');\r
- }\r
- function v6_expand_jcross_clues($direction) {\r
- // $direction: A(cross) or D(own)\r
- $row = NULL;\r
- $r_max = 0;\r
- $c_max = 0;\r
- $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
- $i = 0; // clue index;\r
- $str = '';\r
- for($r=0; $r<=$r_max; $r++) {\r
- for($c=0; $c<=$c_max; $c++) {\r
- $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
- $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
- if ($aword || $dword) {\r
- $i++; // increment clue index\r
-\r
- // get the definition for this word\r
- $def = '';\r
- $word = ($direction=='A') ? $aword : $dword;\r
- $clues = $this->parent->xml_values('data,crossword,clues,item');\r
- foreach ($clues as $clue) {\r
- if ($clue['word'][0]['#']==$word) {\r
- $def = $clue['def'][0]['#'];\r
- $def = strtr($def, array('<'=>'<', '>'=>'>', "\n"=>'<br />'));\r
- break;\r
- }\r
- }\r
-\r
- if (!empty($def)) {\r
- $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>';\r
- }\r
- }\r
- }\r
- }\r
- return $str;\r
- }\r
-\r
- // jcross6.js_\r
-\r
- function v6_expand_LetterArray() {\r
- $row = NULL;\r
- $r_max = 0;\r
- $c_max = 0;\r
- $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
- $str = '';\r
- for($r=0; $r<=$r_max; $r++) {\r
- $str .= "L[$r] = new Array(";\r
- for($c=0; $c<=$c_max; $c++) {\r
- $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'";\r
- }\r
- $str .= ");\n";\r
- }\r
- return $str;\r
- }\r
- function v6_expand_GuessArray() {\r
- $row = NULL;\r
- $r_max = 0;\r
- $c_max = 0;\r
- $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
- $str = '';\r
- for($r=0; $r<=$r_max; $r++) {\r
- $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n";\r
- }\r
- return $str;\r
- }\r
- function v6_expand_ClueNumArray() {\r
- $row = NULL;\r
- $r_max = 0;\r
- $c_max = 0;\r
- $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
- $i = 0; // clue index\r
- $str = '';\r
- for($r=0; $r<=$r_max; $r++) {\r
- $str .= "CL[$r] = new Array(";\r
- for($c=0; $c<=$c_max; $c++) {\r
- if ($c>0) {\r
- $str .= ',';\r
- }\r
- $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
- $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
- if (empty($aword) && empty($dword)) {\r
- $str .= 0;\r
- } else {\r
- $i++; // increment the clue index\r
- $str .= $i;\r
- }\r
- }\r
- $str .= ");\n";\r
- }\r
- return $str;\r
- }\r
- function v6_expand_GridBody() {\r
- $row = NULL;\r
- $r_max = 0;\r
- $c_max = 0;\r
- $this->v6_get_jcross_grid($row, $r_max, $c_max);\r
-\r
- $i = 0; // clue index;\r
- $str = '';\r
- for($r=0; $r<=$r_max; $r++) {\r
- $str .= '<tr id="Row_'.$r.'">';\r
- for($c=0; $c<=$c_max; $c++) {\r
- if (empty($row[$r]['cell'][$c]['#'])) {\r
- $str .= '<td class="BlankCell"> </td>';\r
- } else {\r
- $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);\r
- $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);\r
- if (empty($aword) && empty($dword)) {\r
- $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'"> </span></td>';\r
- } else {\r
- $i++; // increment clue index\r
- $str .= '<td class="NumLetterCell"><a href="javascript:void(0);" class="GridNum" onclick="ShowClue('.$i.','.$r.','.$c.')">'.$i.'</a><span class="NumLetterCellText" id="L_'.$r.'_'.$c.'" onclick="ShowClue('.$i.','.$r.','.$c.')"> </span></td>';\r
- }\r
- }\r
- }\r
- $str .= '</tr>';\r
- }\r
- return $str;\r
- }\r
- function v6_get_jcross_grid(&$row, &$r_max, &$c_max) {\r
- $row = $this->parent->xml_values('data,crossword,grid,row');\r
- $r_max = 0;\r
- $c_max = 0;\r
- if (isset($row) && is_array($row)) {\r
- for($r=0; $r<count($row); $r++) {\r
- if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) {\r
- for($c=0; $c<count($row[$r]['cell']); $c++) {\r
- if (!empty($row[$r]['cell'][$c]['#'])) {\r
- $r_max = max($r, $r_max);\r
- $c_max = max($c, $c_max);\r
- }\r
- } // end for $c\r
- }\r
- } // end for $r\r
- }\r
- }\r
- function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) {\r
- $str = '';\r
- if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) {\r
- $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true);\r
- }\r
- return $str;\r
- }\r
- function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) {\r
- $str = '';\r
- if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) {\r
- $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false);\r
- }\r
- return $str;\r
- }\r
- function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) {\r
- $str = '';\r
- while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) {\r
- $str .= $row[$r]['cell'][$c]['#'];\r
- if ($go_down) {\r
- $r++;\r
- } else {\r
- $c++;\r
- }\r
- }\r
- return $str;\r
- }\r
-\r
- // specials (JQuiz)\r
-\r
- function v6_expand_QuestionOutput() {\r
- $str = '';\r
- $str .= '<ol class="QuizQuestions" id="Questions">'."\n";\r
-\r
- $q = 0;\r
- $tags = 'data,questions,question-record';\r
- while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
-\r
- // get question\r
- $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']");\r
- $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");\r
-\r
- // check we have a question\r
- if ($question_text && $question_type) {\r
-\r
- $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">';\r
- $str .= '<p class="QuestionText">'.$question_text.'</p>';\r
-\r
- if (\r
- $question_type==HOTPOT_JQUIZ_SHORTANSWER || \r
- $question_type==HOTPOT_JQUIZ_HYBRID\r
- ) {\r
- $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>';\r
- $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="9"></input><br /><br />';\r
-\r
- $caption = $this->v6_expand_CheckCaption();\r
- $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)");\r
-\r
- if ($this->v6_expand_Hint()) {\r
- $caption = $this->v6_expand_HintCaption();\r
- $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)");\r
- }\r
-\r
- if ($this->v6_expand_ShowAnswer()) {\r
- $caption = $this->v6_expand_ShowAnswerCaption();\r
- $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)");\r
- }\r
-\r
- $str .= '</div></form></div>';\r
- }\r
-\r
- if (\r
- $question_type==HOTPOT_JQUIZ_MULTICHOICE || \r
- $question_type==HOTPOT_JQUIZ_HYBRID ||\r
- $question_type==HOTPOT_JQUIZ_MULTISELECT\r
- ) {\r
-\r
- switch ($question_type) {\r
- case HOTPOT_JQUIZ_MULTICHOICE: \r
- $str .= '<ol class="MCAnswers">'."\n";\r
- break;\r
- case HOTPOT_JQUIZ_HYBRID:\r
- $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n";\r
- break;\r
- case HOTPOT_JQUIZ_MULTISELECT:\r
- $str .= '<ol class="MSelAnswers">'."\n";\r
- break;\r
- }\r
-\r
- $a = 0;\r
- $aa = 0;\r
- $answers = $question."['answers'][0]['#']";\r
- while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {\r
- $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");\r
- if ($text) {\r
- switch ($question_type) {\r
- case HOTPOT_JQUIZ_MULTICHOICE:\r
- case HOTPOT_JQUIZ_HYBRID:\r
- $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");\r
- if ($include) {\r
- $str .= '<li id="Q_'.$q.'_'.$aa.'"><button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" id="Q_'.$q.'_'.$aa.'_Btn" onclick="CheckMCAnswer('.$q.','.$aa.',this)"> ? </button> '.$text.'</li>'."\n";\r
- }\r
- break;\r
- case HOTPOT_JQUIZ_MULTISELECT:\r
- $str .= '<li id="Q_'.$q.'_'.$aa.'"><form method="post" action="" onsubmit="return false;"><div><input type="checkbox" id="Q_'.$q.'_'.$aa.'_Chk" class="MSelCheckbox" />'.$text.'</div></form></li>'."\n";\r
- break;\r
- }\r
- $aa++;\r
- }\r
- $a++;\r
- }\r
-\r
- $str .= '</ol>';\r
-\r
- if ($question_type==HOTPOT_JQUIZ_MULTISELECT) {\r
- $caption = $this->v6_expand_CheckCaption();\r
- $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)");\r
- }\r
- }\r
-\r
- $str .= "</li>\n";\r
- }\r
- $q++;\r
-\r
- } // end while $question\r
-\r
- $str .= "</ol>\n";\r
- return $str;\r
- }\r
-\r
- function v6_expand_jquiz_button($caption, $onclick) {\r
- return '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="'.$onclick.'">'.$caption.'</button>';\r
- }\r
-\r
- // jquiz.js_\r
-\r
- function v6_expand_MultiChoice() {\r
- return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE);\r
- }\r
- function v6_expand_ShortAnswer() {\r
- return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER);\r
- }\r
- function v6_expand_MultiSelect() {\r
- return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT);\r
- }\r
- function v6_jquiz_question_type($type) {\r
- // does this quiz have any questions of the given $type?\r
- $flag = false;\r
-\r
- $q = 0;\r
- $tags = 'data,questions,question-record';\r
- while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) {\r
- $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");\r
- if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) {\r
- $flag = true;\r
- break;\r
- }\r
- $q++;\r
- }\r
- return $flag;\r
- }\r
- function v6_expand_CorrectFirstTime() {\r
- return $this->js_value('hotpot-config-file,global,correct-first-time');\r
- }\r
- function v6_expand_ContinuousScoring() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring');\r
- }\r
- function v6_expand_ShowCorrectFirstTime() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time');\r
- }\r
- function v6_expand_ShuffleAs() {\r
- return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers');\r
- }\r
-\r
- function v6_expand_DefaultRight() {\r
- return $this->v6_expand_GuessCorrect();\r
- }\r
- function v6_expand_DefaultWrong() {\r
- return $this->v6_expand_GuessIncorrect();\r
- }\r
- function v6_expand_ShowAllQuestionsCaptionJS() {\r
- return $this->v6_expand_ShowAllQuestionsCaption();\r
- }\r
- function v6_expand_ShowOneByOneCaptionJS() {\r
- return $this->v6_expand_ShowOneByOneCaption();\r
- }\r
-\r
- // hp6checkshortanswers.js_ (JQuiz)\r
-\r
- function v6_expand_CorrectList() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers');\r
- }\r
- function v6_expand_HybridTries() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q');\r
- }\r
- function v6_expand_PleaseEnter() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess');\r
- }\r
- function v6_expand_PartlyIncorrect() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect');\r
- }\r
- function v6_expand_ShowAnswerCaption() {\r
- return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption');\r
- }\r
- function v6_expand_ShowAlsoCorrect() {\r
- return $this->bool_value('hotpot-config-file,global,show-also-correct');\r
- }\r
-\r
-} // end class\r
-function hotpot_sort_keypad_chars($a, $b) {\r
- $a = hotpot_keypad_sort_value($a);\r
- $b = hotpot_keypad_sort_value($b);\r
- return ($a<$b) ? -1 : ($a==$b ? 0 : 1);\r
-}\r
-function hotpot_keypad_sort_value($char) {\r
-\r
- // hexadecimal\r
- if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) {\r
- $ord = hexdec($matches[1]);\r
-\r
- // decimal\r
- } else if (preg_match('|&#(\d+);|i', $char, $matches)) {\r
- $ord = intval($matches[1]);\r
-\r
- // other html entity\r
- } else if (preg_match('|&[^;]+;|', $char, $matches)) {\r
- $char = html_entity_decode($matches[0]);\r
- $ord = empty($char) ? 0 : ord($char);\r
-\r
- // not an html entity\r
- } else {\r
- $char = trim($char);\r
- $ord = empty($char) ? 0 : ord($char);\r
- }\r
-\r
- // lowercase letters (plain or accented)\r
- if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) {\r
- $sort_value = ($ord-31).'.'.sprintf('%04d', $ord);\r
-\r
- // all other characters\r
- } else {\r
- $sort_value = $ord;\r
- }\r
-\r
- return $sort_value;\r
-} \r
-\r
-?>\r
+<?PHP
+
+class hotpot_xml_quiz_template extends hotpot_xml_template_default {
+
+ // constructor function for this class
+ function hotpot_xml_quiz_template(&$parent) {
+
+ $this->parent = &$parent;
+
+ $get_js = optional_param('js', false);
+ $get_css = optional_param('css', false);
+
+ if (!empty($get_css)) {
+ // set $this->css
+ $this->v6_expand_StyleSheet();
+
+ } else if (!empty($get_js)) {
+ // set $this->js
+ $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.js_', 'js');
+
+ } else {
+ // set $this->html
+ $this->read_template($this->parent->draganddrop.$this->parent->quiztype.'6.ht_', 'html');
+ }
+
+ // expand special strings, if any
+ $pattern = '';
+ switch ($this->parent->quiztype) {
+ case 'jcloze':
+ $pattern = '/\[(PreloadImageList)\]/';
+ break;
+ case 'jcross':
+ $pattern = '/\[(PreloadImageList|ShowHideClueList)\]/';
+ break;
+ case 'jmatch':
+ $pattern = '/\[(PreloadImageList|QsToShow|FixedArray|DragArray)\]/';
+ break;
+ case 'jmix':
+ $pattern = '/\[(PreloadImageList|SegmentArray|AnswerArray)\]/';
+ break;
+ case 'jquiz':
+ $pattern = '/\[(PreloadImageList|QsToShow)\]/';
+ break;
+ }
+ if (!empty($pattern)) {
+ $this->expand_strings('html', $pattern);
+ }
+ }
+
+ // captions and messages
+
+ function v6_expand_AlsoCorrect() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
+ }
+ function v6_expand_CapitalizeFirst() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',capitalize-first-letter');
+ }
+ function v6_expand_CheckCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,check-caption');
+ }
+ function v6_expand_CorrectIndicator() {
+ return $this->js_value('hotpot-config-file,global,correct-indicator');
+ }
+ function v6_expand_Back() {
+ return $this->int_value('hotpot-config-file,global,include-back');
+ }
+ function v6_expand_BackCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,back-caption');
+ }
+ function v6_expand_ClickToAdd() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',click-to-add');
+ }
+ function v6_expand_ClueCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,clue-caption');
+ }
+ function v6_expand_Clues() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clues');
+ }
+ function v6_expand_Contents() {
+ return $this->int_value('hotpot-config-file,global,include-contents');
+ }
+ function v6_expand_ContentsCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,contents-caption');
+ }
+ function v6_expand_GuessCorrect() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-correct');
+ }
+ function v6_expand_GuessIncorrect() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guess-incorrect');
+ }
+ function v6_expand_Hint() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-hint');
+ }
+ function v6_expand_HintCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,hint-caption');
+ }
+ function v6_expand_IncorrectIndicator() {
+ return $this->js_value('hotpot-config-file,global,incorrect-indicator');
+ }
+ function v6_expand_LastQCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,last-q-caption');
+ }
+ function v6_expand_NextCorrect() {
+ $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-part');
+ if (empty($value)) { // jquiz
+ $value = $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
+ }
+ return $value;
+ }
+ function v6_expand_NextEx() {
+ return $this->int_value('hotpot-config-file,global,include-next-ex');
+ }
+ function v6_expand_NextExCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,next-ex-caption');
+ }
+ function v6_expand_NextQCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,next-q-caption');
+ }
+ function v6_expand_OKCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,ok-caption');
+ }
+ function v6_expand_Restart() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-restart');
+ }
+ function v6_expand_RestartCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,restart-caption');
+ }
+ function v6_expand_ShowAllQuestionsCaption() {
+ return $this->js_value('hotpot-config-file,global,show-all-questions-caption');
+ }
+ function v6_expand_ShowOneByOneCaption() {
+ return $this->js_value('hotpot-config-file,global,show-one-by-one-caption');
+ }
+ function v6_expand_TheseAnswersToo() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',also-correct');
+ }
+ function v6_expand_ThisMuch() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',this-much-correct');
+ }
+ function v6_expand_Undo() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-undo');
+ }
+ function v6_expand_UndoCaption() {
+ return $this->parent->xml_value('hotpot-config-file,global,undo-caption');
+ }
+ function v6_expand_YourScoreIs() {
+ return $this->js_value('hotpot-config-file,global,your-score-is');
+ }
+
+ // reading
+
+ function v6_expand_Reading() {
+ return $this->int_value('data,reading,include-reading');
+ }
+ function v6_expand_ReadingText() {
+ $title = $this->v6_expand_ReadingTitle();
+ $value = $this->parent->xml_value('data,reading,reading-text');
+ $value = empty($value) ? '' : ('<div class="ReadingText">'.$value.'</div>');
+ return $title.$value;
+ }
+ function v6_expand_ReadingTitle() {
+ $value = $this->parent->xml_value('data,reading,reading-title');
+ return empty($value) ? '' : ('<h3 class="ExerciseSubtitle">'.$value.'</h3>');
+ }
+
+ // timer
+
+ function v6_expand_Timer() {
+ return $this->int_value('data,timer,include-timer');
+ }
+ function v6_expand_JSTimer() {
+ return $this->read_template('hp6timer.js_');
+ }
+ function v6_expand_Seconds() {
+ return $this->parent->xml_value('data,timer,seconds');
+ }
+
+ // send results
+
+ function v6_expand_SendResults() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',send-email');
+ }
+ function v6_expand_JSSendResults() {
+ return $this->read_template('hp6sendresults.js_');
+ }
+ function v6_expand_FormMailURL() {
+ return $this->parent->xml_value('hotpot-config-file,global,formmail-url');
+ }
+ function v6_expand_EMail() {
+ return $this->parent->xml_value('hotpot-config-file,global,email');
+ }
+ function v6_expand_NamePlease() {
+ return $this->js_value('hotpot-config-file,global,name-please');
+ }
+
+ // preload images
+
+ function v6_expand_PreloadImages() {
+ $value = $this->v6_expand_PreloadImageList();
+ return empty($value) ? false : true;
+ }
+ function v6_expand_PreloadImageList() {
+
+ // check it has not been set already
+ if (!isset($this->PreloadImageList)) {
+
+ // the list of image urls
+ $list = array();
+
+ // extract <img> tags
+ $img_tag = htmlspecialchars('|<img.*?src="(.*?)".*?>|is');
+ if (preg_match_all($img_tag, $this->parent->source, $matches)) {
+ $list = $matches[1];
+
+ // remove duplicates
+ $list = array_unique($list);
+ }
+
+ // convert to comma delimited string
+ $this->PreloadImageList = empty($list) ? '' : "'".implode(',', $list)."'";
+ }
+ return $this->PreloadImageList;
+ }
+
+ // html files (all quiz types)
+
+ function v6_expand_PlainTitle() {
+ return $this->parent->xml_value('data,title');
+ }
+ function v6_expand_ExerciseSubtitle() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',exercise-subtitle');
+ }
+ function v6_expand_Instructions() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',instructions');
+ }
+ function v6_expand_DublinCoreMetadata() {
+ $dc = '<link rel="schema.DC" href="'.$this->parent->xml_value('', "['rdf:RDF'][0]['@']['xmlns:dc']").'" />'."\n";
+ if (is_string($this->parent->xml_value('rdf:RDF,rdf:Description'))) {
+ // do nothing (there is no more dc info)
+ } else {
+ $dc .= '<meta name="DC:Creator" content="'.$this->parent->xml_value('rdf:RDF,rdf:Description,dc:creator').'" />'."\n";
+ $dc .= '<meta name="DC:Title" content="'.strip_tags($this->parent->xml_value('rdf:RDF,rdf:Description,dc:title')).'" />'."\n";
+ }
+ return $dc;
+ }
+ function v6_expand_FullVersionInfo() {
+ global $CFG;
+ require_once($CFG->hotpotroot.DIRECTORY_SEPARATOR.'version.php'); // set $module
+ return $this->parent->xml_value('version').'.x (Moodle '.$CFG->release.', hotpot-module '.$this->parent->obj_value($module, 'release').')';
+ }
+ function v6_expand_HeaderCode() {
+ return $this->parent->xml_value('hotpot-config-file,global,header-code');
+ }
+ function v6_expand_StyleSheet() {
+ $this->read_template('hp6.cs_', 'css');
+ $this->css = hotpot_convert_stylesheets_urls($this->parent->get_baseurl(), $this->parent->reference, $this->css);
+ return $this->css;
+ }
+
+ // stylesheet (hp6.cs_)
+
+ function v6_expand_PageBGColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
+ }
+ function v6_expand_GraphicURL() {
+ return $this->parent->xml_value('hotpot-config-file,global,graphic-url');
+ }
+ function v6_expand_ExBGColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+ }
+
+ function v6_expand_FontFace() {
+ return $this->parent->xml_value('hotpot-config-file,global,font-face');
+ }
+ function v6_expand_FontSize() {
+ return $this->parent->xml_value('hotpot-config-file,global,font-size');
+ }
+ function v6_expand_TextColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,text-color');
+ }
+ function v6_expand_TitleColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,title-color');
+ }
+ function v6_expand_LinkColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,link-color');
+ }
+ function v6_expand_VLinkColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,vlink-color');
+ }
+
+ function v6_expand_NavTextColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,page-bg-color');
+ }
+ function v6_expand_NavBarColor() {
+ return $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+ }
+ function v6_expand_NavLightColor() {
+ $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+ return $this->get_halfway_color($color, '#ffffff');
+ }
+ function v6_expand_NavShadeColor() {
+ $color = $this->parent->xml_value('hotpot-config-file,global,nav-bar-color');
+ return $this->get_halfway_color($color, '#000000');
+ }
+
+ function v6_expand_FuncLightColor() { // top-left of buttons
+ $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+ return $this->get_halfway_color($color, '#ffffff');
+ }
+ function v6_expand_FuncShadeColor() { // bottom right of buttons
+ $color = $this->parent->xml_value('hotpot-config-file,global,ex-bg-color');
+ return $this->get_halfway_color($color, '#000000');
+ }
+
+ // navigation buttons
+
+ function v6_expand_NavButtons() {
+ $back = $this->v6_expand_Back();
+ $next_ex = $this->v6_expand_NextEx();
+ $contents = $this->v6_expand_Contents();
+ return (empty($back) && empty($next_ex) && empty($contents) ? false : true);
+ }
+ function v6_expand_NavBarJS() {
+ return $this->v6_expand_NavButtons();
+ }
+
+ // js files (all quiz types)
+
+ function v6_expand_JSBrowserCheck() {
+ return $this->read_template('hp6browsercheck.js_');
+ }
+ function v6_expand_JSButtons() {
+ return $this->read_template('hp6buttons.js_');
+ }
+ function v6_expand_JSCard() {
+ return $this->read_template('hp6card.js_');
+ }
+ function v6_expand_JSCheckShortAnswer() {
+ return $this->read_template('hp6checkshortanswer.js_');
+ }
+ function v6_expand_JSHotPotNet() {
+ return $this->read_template('hp6hotpotnet.js_');
+ }
+ function v6_expand_JSShowMessage() {
+ return $this->read_template('hp6showmessage.js_');
+ }
+ function v6_expand_JSUtilities() {
+ return $this->read_template('hp6utilities.js_');
+ }
+
+ // js files
+
+ function v6_expand_JSJCloze6() {
+ return $this->read_template('jcloze6.js_');
+ }
+ function v6_expand_JSJCross6() {
+ return $this->read_template('jcross6.js_');
+ }
+ function v6_expand_JSJMatch6() {
+ return $this->read_template('jmatch6.js_');
+ }
+ function v6_expand_JSJMix6() {
+ return $this->read_template('jmix6.js_');
+ }
+ function v6_expand_JSJQuiz6() {
+ return $this->read_template('jquiz6.js_');
+ }
+
+ // drag and drop
+
+ function v6_expand_JSDJMatch6() {
+ return $this->read_template('djmatch6.js_');
+ }
+ function v6_expand_JSDJMix6() {
+ return $this->read_template('djmix6.js_');
+ }
+
+ // what are these for?
+
+ function v6_expand_JSFJMatch6() {
+ return $this->read_template('fjmatch6.js_');
+ }
+ function v6_expand_JSFJMix6() {
+ return $this->read_template('fjmix6.js_');
+ }
+
+ // jmatch6.js_
+
+ function v6_expand_ShuffleQs() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-questions');
+ }
+ function v6_expand_QsToShow() {
+ $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-limited-questions');
+ if ($i) {
+ $i = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',questions-to-show');
+ }
+ if (empty($i)) {
+ $i = 0;
+ switch ($this->parent->quiztype) {
+ case 'jmatch':
+ $values = $this->parent->xml_values('data,matching-exercise,pair');
+ $i = count($values);
+ break;
+ case 'jquiz':
+ while ($this->parent->xml_value('data,questions,question-record', "[$i]['#']['question'][0]['#']")) {
+ $i++;
+ }
+ break;
+ } // end switch
+ }
+ return $i;
+ }
+ function v6_expand_MatchDivItems() {
+ $l_items = array();
+ $r_items = array();
+ $this->get_jmatch_items($l_items, $r_items);
+
+ $l_keys = $this->shuffle_jmatch_items($l_items);
+ $r_keys = $this->shuffle_jmatch_items($r_items);
+
+ $options = '<option value="x">'.$this->parent->xml_value('data,matching-exercise,default-right-item').'</option>';
+ foreach ($r_keys as $key) {
+ $options .= '<option value="'.$key.'">'.$r_items[$key]['text'][0]['#'].'</option>'."\n";
+ }
+
+ $str = '';
+ foreach ($l_keys as $key) {
+ $str .= '<tr><td class="LeftItem">'.$l_items[$key]['text'][0]['#'].'</td>';
+ $str .= '<td class="RightItem"><select id="s'.$key.'_'.$key.'">'.$options.'</select></td>';
+ $str .= '<td></td></tr>';
+ }
+ return $str;
+ }
+
+ // jmix6.js_
+
+ function v6_expand_Punctuation() {
+ $tags = 'data,jumbled-order-exercise';
+ $chars = array_merge(
+ $this->jmix_Punctuation("$tags,main-order,segment"),
+ $this->jmix_Punctuation("$tags,alternate")
+ );
+ $chars = array_unique($chars);
+ $chars = implode('', $chars);
+ $chars = $this->js_safe($chars, true);
+ return $chars;
+ }
+ function jmix_Punctuation($tags) {
+ $chars = array();
+
+ // all punctutation except '&#;' (because they are used in html entities)
+ $ENTITIES = $this->jmix_encode_punctuation('!"$%'."'".'()*+,-./:<=>?@[\]^_`{|}~');
+ $pattern = "/&#x([0-9A-F]+);/i";
+ $i = 0;
+
+ // get next segment (or alternate answer)
+ while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+
+ // convert low-ascii punctuation to entities
+ $value = strtr($value, $ENTITIES);
+
+ // extract all hex HTML entities
+ if (preg_match_all($pattern, $value, $matches)) {
+
+ // loop through hex entities
+ $m_max = count($matches[0]);
+ for ($m=0; $m<$m_max; $m++) {
+
+ // convert to hex number
+ eval('$hex=0x'.$matches[1][$m].';');
+
+ // is this a punctuation character?
+ if (
+ ($hex>=0x0020 && $hex<=0x00BF) || // ascii punctuation
+ ($hex>=0x2000 && $hex<=0x206F) || // general punctuation
+ ($hex>=0x3000 && $hex<=0x303F) || // CJK punctuation
+ ($hex>=0xFE30 && $hex<=0xFE4F) || // CJK compatability
+ ($hex>=0xFE50 && $hex<=0xFE6F) || // small form variants
+ ($hex>=0xFF00 && $hex<=0xFF40) || // halfwidth and fullwidth forms (1)
+ ($hex>=0xFF5B && $hex<=0xFF65) || // halfwidth and fullwidth forms (2)
+ ($hex>=0xFFE0 && $hex<=0xFFEE) // halfwidth and fullwidth forms (3)
+ ) {
+ // add this character
+ $chars[] = $matches[0][$m];
+ }
+ }
+ }
+ $i++;
+ }
+
+ return $chars;
+ }
+ function v6_expand_OpenPunctuation() {
+ $tags = 'data,jumbled-order-exercise';
+ $chars = array_merge(
+ $this->jmix_OpenPunctuation("$tags,main-order,segment"),
+ $this->jmix_OpenPunctuation("$tags,alternate")
+ );
+ $chars = array_unique($chars);
+ $chars = implode('', $chars);
+ $chars = $this->js_safe($chars, true);
+ return $chars;
+ }
+ function jmix_OpenPunctuation($tags) {
+ $chars = array();
+
+ // unicode punctuation designations (pi="initial quote", ps="open")
+ // http://www.sql-und-xml.de/unicode-database/pi.html
+ // http://www.sql-und-xml.de/unicode-database/ps.html
+ $pi = '0022|0027|00AB|2018|201B|201C|201F|2039';
+ $ps = '0028|005B|007B|0F3A|0F3C|169B|201A|201E|2045|207D|208D|2329|23B4|2768|276A|276C|276E|2770|2772|2774|27E6|27E8|27EA|2983|2985|2987|2989|298B|298D|298F|2991|2993|2995|2997|29D8|29DA|29FC|3008|300A|300C|300E|3010|3014|3016|3018|301A|301D|FD3E|FE35|FE37|FE39|FE3B|FE3D|FE3F|FE41|FE43|FE47|FE59|FE5B|FE5D|FF08|FF3B|FF5B|FF5F|FF62';
+ $pattern = "/(&#x($pi|$ps);)/i";
+
+ $ENTITIES = $this->jmix_encode_punctuation('"'."'".'(<[{');
+
+ $i = 0;
+ while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+ $value = strtr($value, $ENTITIES);
+ if (preg_match_all($pattern, $value, $matches)) {
+ $chars = array_merge($chars, $matches[0]);
+ }
+ $i++;
+ }
+
+ return $chars;
+ }
+ function jmix_encode_punctuation($str) {
+ $ENTITIES = array();
+ $i_max = strlen($str);
+ for ($i=0; $i<$i_max; $i++) {
+ $ENTITIES[$str{$i}] = '&#x'.sprintf('%04X', ord($str{$i})).';';
+ }
+ return $ENTITIES;
+ }
+ function v6_expand_ExerciseTitle() {
+ return $this->parent->xml_value('data,title');
+ }
+
+ // Jmix specials
+
+ function v6_expand_SegmentArray() {
+
+ $segments = array();
+ $values = array();
+ $VALUES = array();
+
+ // XML tags to the start of a segment
+ $tags = 'data,jumbled-order-exercise,main-order,segment';
+
+ $i = 0;
+ while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+ $VALUE = strtoupper($value);
+ $key = array_search($VALUE, $VALUES);
+ if (is_numeric($key)) {
+ $segments[] = $key;
+ } else {
+ $segments[] = $i;
+ $values[$i] = $value;
+ $VALUES[$i] = $VALUE;
+ }
+ $i++;
+ }
+
+ $this->seed_random_number_generator();
+ $keys = array_keys($segments);
+ shuffle($keys);
+
+ $str = '';
+ for($i=0; $i<count($keys); $i++) {
+ $key = $segments[$keys[$i]];
+ $str .= "Segments[$i] = new Array();\n";
+ $str .= "Segments[$i][0] = '".$this->js_safe($values[$key], true)."';\n";
+ $str .= "Segments[$i][1] = ".($key+1).";\n";
+ $str .= "Segments[$i][2] = 0;\n";
+ }
+ return $str;
+ }
+ function v6_expand_AnswerArray() {
+
+ $segments = array();
+ $values = array();
+ $VALUES = array();
+ $escapedvalues = array();
+
+ // XML tags to the start of a segment
+ $tags = 'data,jumbled-order-exercise,main-order,segment';
+
+ $i = 0;
+ while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+ $VALUE = strtoupper($value);
+ $key = array_search($VALUE, $VALUES);
+ if (is_numeric($key)) {
+ $segments[] = $key+1;
+ } else {
+ $segments[] = $i+1;
+ $values[$i] = $value;
+ $VALUES[$i] = $VALUE;
+ $escapedvalues[] = preg_quote($value, '/');
+ }
+ $i++;
+ }
+
+ // start the answers array
+ $a = 0;
+ $str = 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
+
+ // pattern to match the next part of an alternate answer
+ $pattern = '/^('.implode('|', $escapedvalues).')\\s*/i';
+
+ // XML tags to the start of an alternate answer
+ $tags = 'data,jumbled-order-exercise,alternate';
+
+ $i = 0;
+ while ($value = $this->parent->xml_value($tags, "[$i]['#']")) {
+ $segments = array();
+ while (strlen($value) && preg_match($pattern, $value, $matches)) {
+ $key = array_search($matches[1], $values);
+ if (is_numeric($key)) {
+ $segments[] = $key+1;
+ $value = substr($value, strlen($matches[0]));
+ } else {
+ // invalid alternate sequence
+ $segments = array();
+ break;
+ }
+ }
+ if (count($segments)) {
+ $str .= 'Answers['.($a++).'] = new Array('.implode(',', $segments).");\n";
+ }
+ $i++;
+ }
+ return $str;
+ }
+
+ // ===============================================================
+
+ // JMix (jmix6.js_)
+
+ function v6_expand_RemainingWords() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',remaining-words');
+ }
+ function v6_expand_TimesUp() {
+ return $this->parent->xml_value('hotpot-config-file,global,times-up');
+ }
+
+ // nav bar
+
+ function v6_expand_NavBar($navbarid='') {
+ $this->navbarid = $navbarid;
+
+ $tag = 'navbar';
+ $this->read_template('hp6navbar.ht_', $tag);
+
+ unset($this->navbarid);
+
+ return $this->$tag;
+ }
+ function v6_expand_TopNavBar() {
+ return $this->v6_expand_NavBar('TopNavBar');
+ }
+ function v6_expand_BottomNavBar() {
+ return $this->v6_expand_NavBar('BottomNavBar');
+ }
+
+ // hp6navbar.ht_
+
+ function v6_expand_NavBarID() {
+ // $this->navbarid is set in "$this->v6_expand_NavBar"
+ return empty($this->navbarid) ? '' : $this->navbarid;
+ }
+ function v6_expand_ContentsURL() {
+ $url = $this->parent->xml_value('hotpot-config-file,global,contents-url');
+ if ($url) {
+ $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
+ }
+ return $url;
+ }
+ function v6_expand_NextExURL() {
+ $url = $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',next-ex-url');
+ if ($url) {
+ $url = hotpot_convert_navbutton_url($this->parent->get_baseurl(), $this->parent->reference, $url, $this->parent->course);
+ }
+ return $url;
+ }
+
+ // conditional blocks
+
+ function v6_expand_ShowAnswer() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-show-answer');
+ }
+ function v6_expand_Slide() {
+ return true; // whats's this (JMatch drag and drop)
+ }
+
+ // specials (JMatch)
+
+ function v6_expand_FixedArray() {
+ $l_items = array();
+ $r_items = array();
+ $this->get_jmatch_items($l_items, $r_items);
+
+ $str = '';
+ foreach ($l_items as $i=>$item) {
+ $str .= "F[$i] = new Array();\n";
+ $str .= "F[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
+ $str .= "F[$i][1] = ".($i+1).";\n";
+ }
+ return $str;
+ }
+ function v6_expand_DragArray() {
+ $l_items = array();
+ $r_items = array();
+ $this->get_jmatch_items($l_items, $r_items);
+
+ $str = '';
+ foreach ($r_items as $i=>$item) {
+ $str .= "D[$i] = new Array();\n";
+ $str .= "D[$i][0] = '".$this->js_safe($item['text'][0]['#'], true)."';\n";
+ $str .= "D[$i][1] = ".($i+1).";\n";
+ $str .= "D[$i][2] = 0;\n";
+ }
+ return $str;
+ }
+
+ function get_jmatch_items(&$l_items, &$r_items) {
+ $tags = 'data,matching-exercise,pair';
+ $i = 0;
+ while($item = $this->parent->xml_value($tags,"[$i]['#']['left-item'][0]['#']")) {
+ if (!empty($item['text'][0]['#'])) {
+ $l_items[] = $item;
+ }
+ $i++;
+ }
+ $i = 0;
+ while($item = $this->parent->xml_value($tags,"[$i]['#']['right-item'][0]['#']")) {
+ if (!empty($item['text'][0]['#'])) {
+ $r_items[] = $item;
+ }
+ $i++;
+ }
+ }
+ function shuffle_jmatch_items(&$items) {
+ // get moveable items
+ $moveable_keys = array();
+ for($i=0; $i<count($items); $i++) {
+ if(empty($items[$i]['fixed'][0]['#'])) {
+ $moveable_keys[] = $i;
+ }
+ }
+ // shuffle moveable items
+ $this->seed_random_number_generator();
+ shuffle($moveable_keys);
+
+ $keys = array();
+ for($i=0, $ii=0; $i<count($items); $i++) {
+ if(empty($items[$i]['fixed'][0]['#'])) {
+ // moveable items are inserted in a shuffled order
+ $keys[] = $moveable_keys[$ii++];
+ } else {
+ // fixed items stay where they are
+ $keys[] = $i;
+ }
+ }
+ return $keys;
+ }
+ function seed_random_number_generator() {
+ static $seeded_RNG = FALSE;
+ if (!$seeded_RNG) {
+ srand((double) microtime() * 1000000);
+ $seeded_RNG = TRUE;
+ }
+ }
+
+ // specials (JMix)
+
+
+ // specials (JCloze)
+
+ function v6_expand_ItemArray() {
+ $q = 0;
+ $str = '';
+ switch ($this->parent->quiztype) {
+ case 'jcloze':
+ $tags = 'data,gap-fill,question-record';
+ while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+ $a = 0;
+ $aa = 0;
+ while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+ $text = $this->js_value($tags, $answer."['text'][0]['#']", true);
+ if (strlen($text)) {
+ if ($aa==0) { // first time only
+ $str .= "\n";
+ $str .= "I[$q] = new Array();\n";
+ $str .= "I[$q][1] = new Array();\n";
+ }
+ $str .= "I[$q][1][$aa] = new Array();\n";
+ $str .= "I[$q][1][$aa][0] = '$text';\n";
+ $aa++;
+ }
+ $a++;
+ }
+ // add clue, if any answers were found
+ if ($aa) {
+ $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
+ $str .= "I[$q][2] = '$clue';\n";
+ }
+ $q++;
+ }
+ break;
+ case 'jquiz':
+ $str .= "I=new Array();\n";
+ $tags = 'data,questions,question-record';
+ while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+ $question_type = $this->int_value($tags, $question."['question-type'][0]['#']");
+ $weighting = $this->int_value($tags, $question."['weighting'][0]['#']");
+ $clue = $this->js_value($tags, $question."['clue'][0]['#']", true);
+
+ $answers = $question."['answers'][0]['#']";
+
+ $a = 0;
+ $aa = 0;
+ while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+ $text = $this->js_value($tags, $answer."['text'][0]['#']", true);
+ $feedback = $this->js_value($tags, $answer."['feedback'][0]['#']", true);
+ $correct = $this->int_value($tags, $answer."['correct'][0]['#']");
+ $percent = $this->int_value($tags, $answer."['percent-correct'][0]['#']");
+ $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
+ if (strlen($text)) {
+ if ($aa==0) { // first time only
+ $str .= "\n";
+ $str .= "I[$q] = new Array();\n";
+ $str .= "I[$q][0] = $weighting;\n";
+ $str .= "I[$q][1] = '$clue';\n";
+ $str .= "I[$q][2] = '".($question_type-1)."';\n";
+ $str .= "I[$q][3] = new Array();\n";
+ }
+ $str .= "I[$q][3][$aa] = new Array('$text','$feedback',$correct,$percent,$include);\n";
+ $aa++;
+ }
+ $a++;
+ }
+ $q++;
+ }
+ break;
+ }
+ return $str;
+ }
+
+ function v6_expand_ClozeBody() {
+ $str = '';
+
+ // get drop down list of words, if required
+ $dropdownlist = '';
+ if ($this->v6_use_DropDownList()) {
+ $this->v6_set_WordList();
+ foreach ($this->wordlist as $word) {
+ $dropdownlist .= '<option value="'.$word.'">'.$word.'</option>';
+ }
+ }
+
+ // cache clues flag and caption
+ $includeclues = $this->v6_expand_Clues();
+ $cluecaption = $this->v6_expand_ClueCaption();
+
+ // detect if cloze starts with gap
+ $strpos = strpos($this->parent->source, '<gap-fill><question-record>');
+ if (is_numeric($strpos)) {
+ $startwithgap = true;
+ } else {
+ $startwithgap = false;
+ }
+
+ // initialize loop values
+ $q = 0;
+ $tags = 'data,gap-fill';
+ $question_record = "$tags,question-record";
+
+ // loop through text and gaps
+ do {
+ $text = $this->parent->xml_value($tags, "[0]['#'][$q]");
+ $gap = '';
+ if (($question="[$q]['#']") && $this->parent->xml_value($question_record, $question)) {
+ $gap .= '<span class="GapSpan" id="GapSpan'.$q.'">';
+ if ($this->v6_use_DropDownList()) {
+ $gap .= '<select id="Gap'.$q.'"><option value=""></option>'.$dropdownlist.'</select>';
+ } else {
+ // minimum gap size
+ $gapsize = 6;
+
+ // increase gap size to length of longest answer for this gap
+ $a = 0;
+ while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($question_record, $answer)) {
+ $answertext = $this->parent->xml_value($question_record, $answer."['text'][0]['#']");
+ $answertext = preg_replace('|&[#a-zA-Z0-9]+;|', 'x', $answertext);
+ $gapsize = max($gapsize, strlen($answertext));
+ $a++;
+ }
+
+ $gap .= '<input type="text" id="Gap'.$q.'" onfocus="TrackFocus('.$q.')" onblur="LeaveGap()" class="GapBox" size="'.$gapsize.'"></input>';
+ }
+ if ($includeclues) {
+ $clue = $this->parent->xml_value($question_record, $question."['clue'][0]['#']");
+ if (strlen($clue)) {
+ $gap .= '<button style="line-height: 1.0" class="FuncButton" onfocus="FuncBtnOver(this)" onmouseover="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="ShowClue('.$q.')">'.$cluecaption.'</button>';
+ }
+ }
+ $gap .= '</span>';
+ }
+ if ($startwithgap) {
+ $str .= "$gap$text";
+ } else {
+ $str .= "$text$gap";
+ }
+ $q++;
+ } while (strlen($text) || strlen($gap));
+
+ return $str;
+ }
+
+ // JCloze quiztype
+
+ function v6_expand_WordList() {
+ $str = '';
+ if ($this->v6_include_WordList()) {
+ $this->v6_set_WordList();
+ $str = implode('    ', $this->wordlist);
+ }
+ return $str;
+ }
+ function v6_include_WordList() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-word-list');
+ }
+ function v6_use_DropDownList() {
+ return $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',use-drop-down-list');
+ }
+ function v6_set_WordList() {
+
+ if (isset($this->wordlist)) {
+ // do nothing
+ } else {
+ $this->wordlist = array();
+
+ // is the wordlist required
+ if ($this->v6_include_WordList() || $this->v6_use_DropDownList()) {
+
+ $q = 0;
+ $tags = 'data,gap-fill,question-record';
+ while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+ $a = 0;
+ $aa = 0;
+ while (($answer=$question."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+ $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");
+ $correct = $this->int_value($tags, $answer."['correct'][0]['#']");
+ if ($text && $correct) { // $correct is always true
+ $this->wordlist[] = $text;
+ $aa++;
+ }
+ $a++;
+ }
+ $q++;
+ }
+ $this->wordlist = array_unique($this->wordlist);
+ sort($this->wordlist);
+ }
+ }
+ }
+ function v6_expand_Keypad() {
+ $str = '';
+ if ($this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-keypad')) {
+
+ // these characters must always be in the keypad
+ $chars = array();
+ $this->add_keypad_chars($chars, $this->parent->xml_value('hotpot-config-file,global,keypad-characters'));
+
+ // append other characters used in the answers
+ $tags = '';
+ switch ($this->parent->quiztype) {
+ case 'jcloze':
+ $tags = 'data,gap-fill,question-record';
+ break;
+ case 'jquiz':
+ $tags = 'data,questions,question-record';
+ break;
+ }
+ if ($tags) {
+ $q = 0;
+ while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+ if ($this->parent->quiztype=='jquiz') {
+ $answers = $question."['answers'][0]['#']";
+ } else {
+ $answers = $question;
+ }
+
+ $a = 0;
+ while (($answer=$answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+ $this->add_keypad_chars($chars, $this->parent->xml_value($tags, $answer."['text'][0]['#']"));
+ $a++;
+ }
+ $q++;
+ }
+ }
+
+ // remove duplicate characters and sort
+ $chars = array_unique($chars);
+ usort($chars, "hotpot_sort_keypad_chars");
+
+ // create keypad buttons for each character
+ $str .= '<div class="Keypad">';
+ foreach ($chars as $char) {
+ $str .= "<button onclick=\"TypeChars('".$this->js_safe($char, true)."'); return false;\">$char</button>";
+ }
+ $str .= '</div>';
+ }
+ return $str;
+ }
+ function add_keypad_chars(&$chars, $text) {
+ if (preg_match_all('|&[^;]+;|i', $text, $more_chars)) {
+ $chars = array_merge($chars, $more_chars[0]);
+ }
+ }
+ function v6_expand_Correct() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-correct');
+ }
+ function v6_expand_Incorrect() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',guesses-incorrect');
+ }
+ function v6_expand_GiveHint() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',next-correct-letter');
+ }
+ function v6_expand_CaseSensitive() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',case-sensitive');
+ }
+
+ // JCross quiztype
+
+ function v6_expand_CluesAcrossLabel() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-across');
+ }
+ function v6_expand_CluesDownLabel() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',clues-down');
+ }
+ function v6_expand_EnterCaption() {
+ return $this->js_value('hotpot-config-file,'.$this->parent->quiztype.',enter-caption');
+ }
+ function v6_expand_ShowHideClueList() {
+ $value = $this->int_value('hotpot-config-file,'.$this->parent->quiztype.',include-clue-list');
+ return empty($value) ? ' style="display: none;"' : '';
+ }
+
+ // JCross specials
+
+ function v6_expand_CluesDown() {
+ return $this->v6_expand_jcross_clues('D');
+ }
+ function v6_expand_CluesAcross() {
+ return $this->v6_expand_jcross_clues('A');
+ }
+ function v6_expand_jcross_clues($direction) {
+ // $direction: A(cross) or D(own)
+ $row = NULL;
+ $r_max = 0;
+ $c_max = 0;
+ $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+ $i = 0; // clue index;
+ $str = '';
+ for($r=0; $r<=$r_max; $r++) {
+ for($c=0; $c<=$c_max; $c++) {
+ $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+ $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+ if ($aword || $dword) {
+ $i++; // increment clue index
+
+ // get the definition for this word
+ $def = '';
+ $word = ($direction=='A') ? $aword : $dword;
+ $clues = $this->parent->xml_values('data,crossword,clues,item');
+ foreach ($clues as $clue) {
+ if ($clue['word'][0]['#']==$word) {
+ $def = $clue['def'][0]['#'];
+ $def = strtr($def, array('<'=>'<', '>'=>'>', "\n"=>'<br />'));
+ break;
+ }
+ }
+
+ if (!empty($def)) {
+ $str .= '<tr><td class="ClueNum">'.$i.'. </td><td id="Clue_'.$direction.'_'.$i.'" class="Clue">'.$def.'</td></tr>';
+ }
+ }
+ }
+ }
+ return $str;
+ }
+
+ // jcross6.js_
+
+ function v6_expand_LetterArray() {
+ $row = NULL;
+ $r_max = 0;
+ $c_max = 0;
+ $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+ $str = '';
+ for($r=0; $r<=$r_max; $r++) {
+ $str .= "L[$r] = new Array(";
+ for($c=0; $c<=$c_max; $c++) {
+ $str .= ($c>0 ? ',' : '')."'".$this->js_safe($row[$r]['cell'][$c]['#'], true)."'";
+ }
+ $str .= ");\n";
+ }
+ return $str;
+ }
+ function v6_expand_GuessArray() {
+ $row = NULL;
+ $r_max = 0;
+ $c_max = 0;
+ $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+ $str = '';
+ for($r=0; $r<=$r_max; $r++) {
+ $str .= "G[$r] = new Array('".str_repeat("','", $c_max)."');\n";
+ }
+ return $str;
+ }
+ function v6_expand_ClueNumArray() {
+ $row = NULL;
+ $r_max = 0;
+ $c_max = 0;
+ $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+ $i = 0; // clue index
+ $str = '';
+ for($r=0; $r<=$r_max; $r++) {
+ $str .= "CL[$r] = new Array(";
+ for($c=0; $c<=$c_max; $c++) {
+ if ($c>0) {
+ $str .= ',';
+ }
+ $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+ $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+ if (empty($aword) && empty($dword)) {
+ $str .= 0;
+ } else {
+ $i++; // increment the clue index
+ $str .= $i;
+ }
+ }
+ $str .= ");\n";
+ }
+ return $str;
+ }
+ function v6_expand_GridBody() {
+ $row = NULL;
+ $r_max = 0;
+ $c_max = 0;
+ $this->v6_get_jcross_grid($row, $r_max, $c_max);
+
+ $i = 0; // clue index;
+ $str = '';
+ for($r=0; $r<=$r_max; $r++) {
+ $str .= '<tr id="Row_'.$r.'">';
+ for($c=0; $c<=$c_max; $c++) {
+ if (empty($row[$r]['cell'][$c]['#'])) {
+ $str .= '<td class="BlankCell"> </td>';
+ } else {
+ $aword = $this->get_jcross_aword($row, $r, $r_max, $c, $c_max);
+ $dword = $this->get_jcross_dword($row, $r, $r_max, $c, $c_max);
+ if (empty($aword) && empty($dword)) {
+ $str .= '<td class="LetterOnlyCell"><span id="L_'.$r.'_'.$c.'"> </span></td>';
+ } else {
+ $i++; // increment clue index
+ $str .= '<td class="NumLetterCell"><a href="javascript:void(0);" class="GridNum" onclick="ShowClue('.$i.','.$r.','.$c.')">'.$i.'</a><span class="NumLetterCellText" id="L_'.$r.'_'.$c.'" onclick="ShowClue('.$i.','.$r.','.$c.')"> </span></td>';
+ }
+ }
+ }
+ $str .= '</tr>';
+ }
+ return $str;
+ }
+ function v6_get_jcross_grid(&$row, &$r_max, &$c_max) {
+ $row = $this->parent->xml_values('data,crossword,grid,row');
+ $r_max = 0;
+ $c_max = 0;
+ if (isset($row) && is_array($row)) {
+ for($r=0; $r<count($row); $r++) {
+ if (isset($row[$r]['cell']) && is_array($row[$r]['cell'])) {
+ for($c=0; $c<count($row[$r]['cell']); $c++) {
+ if (!empty($row[$r]['cell'][$c]['#'])) {
+ $r_max = max($r, $r_max);
+ $c_max = max($c, $c_max);
+ }
+ } // end for $c
+ }
+ } // end for $r
+ }
+ }
+ function get_jcross_dword(&$row, $r, $r_max, $c, $c_max) {
+ $str = '';
+ if (($r==0 || empty($row[$r-1]['cell'][$c]['#'])) && $r<$r_max && !empty($row[$r+1]['cell'][$c]['#'])) {
+ $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, true);
+ }
+ return $str;
+ }
+ function get_jcross_aword(&$row, $r, $r_max, $c, $c_max) {
+ $str = '';
+ if (($c==0 || empty($row[$r]['cell'][$c-1]['#'])) && $c<$c_max && !empty($row[$r]['cell'][$c+1]['#'])) {
+ $str = $this->get_jcross_word($row, $r, $r_max, $c, $c_max, false);
+ }
+ return $str;
+ }
+ function get_jcross_word(&$row, $r, $r_max, $c, $c_max, $go_down=false) {
+ $str = '';
+ while ($r<=$r_max && $c<=$c_max && !empty($row[$r]['cell'][$c]['#'])) {
+ $str .= $row[$r]['cell'][$c]['#'];
+ if ($go_down) {
+ $r++;
+ } else {
+ $c++;
+ }
+ }
+ return $str;
+ }
+
+ // specials (JQuiz)
+
+ function v6_expand_QuestionOutput() {
+ $str = '';
+ $str .= '<ol class="QuizQuestions" id="Questions">'."\n";
+
+ $q = 0;
+ $tags = 'data,questions,question-record';
+ while (($question="[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+
+ // get question
+ $question_text = $this->parent->xml_value($tags, $question."['question'][0]['#']");
+ $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
+
+ // check we have a question
+ if ($question_text && $question_type) {
+
+ $str .= '<li class="QuizQuestion" id="Q_'.$q.'" style="display: none;">';
+ $str .= '<p class="QuestionText">'.$question_text.'</p>';
+
+ if (
+ $question_type==HOTPOT_JQUIZ_SHORTANSWER ||
+ $question_type==HOTPOT_JQUIZ_HYBRID
+ ) {
+ $str .= '<div class="ShortAnswer" id="Q_'.$q.'_SA"><form method="post" action="" onsubmit="return false;"><div>';
+ $str .= '<input type="text" id="Q_'.$q.'_Guess" onfocus="TrackFocus('."'".'Q_'.$q.'_Guess'."'".')" onblur="LeaveGap()" class="ShortAnswerBox" size="9"></input><br /><br />';
+
+ $caption = $this->v6_expand_CheckCaption();
+ $str .= $this->v6_expand_jquiz_button($caption, "CheckShortAnswer($q)");
+
+ if ($this->v6_expand_Hint()) {
+ $caption = $this->v6_expand_HintCaption();
+ $str .= $this->v6_expand_jquiz_button($caption, "ShowHint($q)");
+ }
+
+ if ($this->v6_expand_ShowAnswer()) {
+ $caption = $this->v6_expand_ShowAnswerCaption();
+ $str .= $this->v6_expand_jquiz_button($caption, "ShowAnswers($q)");
+ }
+
+ $str .= '</div></form></div>';
+ }
+
+ if (
+ $question_type==HOTPOT_JQUIZ_MULTICHOICE ||
+ $question_type==HOTPOT_JQUIZ_HYBRID ||
+ $question_type==HOTPOT_JQUIZ_MULTISELECT
+ ) {
+
+ switch ($question_type) {
+ case HOTPOT_JQUIZ_MULTICHOICE:
+ $str .= '<ol class="MCAnswers">'."\n";
+ break;
+ case HOTPOT_JQUIZ_HYBRID:
+ $str .= '<ol class="MCAnswers" id="Q_'.$q.'_Hybrid_MC" style="display: none;">'."\n";
+ break;
+ case HOTPOT_JQUIZ_MULTISELECT:
+ $str .= '<ol class="MSelAnswers">'."\n";
+ break;
+ }
+
+ $a = 0;
+ $aa = 0;
+ $answers = $question."['answers'][0]['#']";
+ while (($answer = $answers."['answer'][$a]['#']") && $this->parent->xml_value($tags, $answer)) {
+ $text = $this->parent->xml_value($tags, $answer."['text'][0]['#']");
+ if ($text) {
+ switch ($question_type) {
+ case HOTPOT_JQUIZ_MULTICHOICE:
+ case HOTPOT_JQUIZ_HYBRID:
+ $include = $this->int_value($tags, $answer."['include-in-mc-options'][0]['#']");
+ if ($include) {
+ $str .= '<li id="Q_'.$q.'_'.$aa.'"><button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" id="Q_'.$q.'_'.$aa.'_Btn" onclick="CheckMCAnswer('.$q.','.$aa.',this)"> ? </button> '.$text.'</li>'."\n";
+ }
+ break;
+ case HOTPOT_JQUIZ_MULTISELECT:
+ $str .= '<li id="Q_'.$q.'_'.$aa.'"><form method="post" action="" onsubmit="return false;"><div><input type="checkbox" id="Q_'.$q.'_'.$aa.'_Chk" class="MSelCheckbox" />'.$text.'</div></form></li>'."\n";
+ break;
+ }
+ $aa++;
+ }
+ $a++;
+ }
+
+ $str .= '</ol>';
+
+ if ($question_type==HOTPOT_JQUIZ_MULTISELECT) {
+ $caption = $this->v6_expand_CheckCaption();
+ $str .= $this->v6_expand_jquiz_button($caption, "CheckMultiSelAnswer($q)");
+ }
+ }
+
+ $str .= "</li>\n";
+ }
+ $q++;
+
+ } // end while $question
+
+ $str .= "</ol>\n";
+ return $str;
+ }
+
+ function v6_expand_jquiz_button($caption, $onclick) {
+ return '<button class="FuncButton" onfocus="FuncBtnOver(this)" onblur="FuncBtnOut(this)" onmouseover="FuncBtnOver(this)" onmouseout="FuncBtnOut(this)" onmousedown="FuncBtnDown(this)" onmouseup="FuncBtnOut(this)" onclick="'.$onclick.'">'.$caption.'</button>';
+ }
+
+ // jquiz.js_
+
+ function v6_expand_MultiChoice() {
+ return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTICHOICE);
+ }
+ function v6_expand_ShortAnswer() {
+ return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_SHORTANSWER);
+ }
+ function v6_expand_MultiSelect() {
+ return $this->v6_jquiz_question_type(HOTPOT_JQUIZ_MULTISELECT);
+ }
+ function v6_jquiz_question_type($type) {
+ // does this quiz have any questions of the given $type?
+ $flag = false;
+
+ $q = 0;
+ $tags = 'data,questions,question-record';
+ while (($question = "[$q]['#']") && $this->parent->xml_value($tags, $question)) {
+ $question_type = $this->parent->xml_value($tags, $question."['question-type'][0]['#']");
+ if ($question_type==$type || ($question_type==HOTPOT_JQUIZ_HYBRID && ($type==HOTPOT_JQUIZ_MULTICHOICE || $type==HOTPOT_JQUIZ_SHORTANSWER))) {
+ $flag = true;
+ break;
+ }
+ $q++;
+ }
+ return $flag;
+ }
+ function v6_expand_CorrectFirstTime() {
+ return $this->js_value('hotpot-config-file,global,correct-first-time');
+ }
+ function v6_expand_ContinuousScoring() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',continuous-scoring');
+ }
+ function v6_expand_ShowCorrectFirstTime() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',show-correct-first-time');
+ }
+ function v6_expand_ShuffleAs() {
+ return $this->bool_value('hotpot-config-file,'.$this->parent->quiztype.',shuffle-answers');
+ }
+
+ function v6_expand_DefaultRight() {
+ return $this->v6_expand_GuessCorrect();
+ }
+ function v6_expand_DefaultWrong() {
+ return $this->v6_expand_GuessIncorrect();
+ }
+ function v6_expand_ShowAllQuestionsCaptionJS() {
+ return $this->v6_expand_ShowAllQuestionsCaption();
+ }
+ function v6_expand_ShowOneByOneCaptionJS() {
+ return $this->v6_expand_ShowOneByOneCaption();
+ }
+
+ // hp6checkshortanswers.js_ (JQuiz)
+
+ function v6_expand_CorrectList() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',correct-answers');
+ }
+ function v6_expand_HybridTries() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',short-answer-tries-on-hybrid-q');
+ }
+ function v6_expand_PleaseEnter() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',enter-a-guess');
+ }
+ function v6_expand_PartlyIncorrect() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',partly-incorrect');
+ }
+ function v6_expand_ShowAnswerCaption() {
+ return $this->parent->xml_value('hotpot-config-file,'.$this->parent->quiztype.',show-answer-caption');
+ }
+ function v6_expand_ShowAlsoCorrect() {
+ return $this->bool_value('hotpot-config-file,global,show-also-correct');
+ }
+
+} // end class
+function hotpot_sort_keypad_chars($a, $b) {
+ $a = hotpot_keypad_sort_value($a);
+ $b = hotpot_keypad_sort_value($b);
+ return ($a<$b) ? -1 : ($a==$b ? 0 : 1);
+}
+function hotpot_keypad_sort_value($char) {
+
+ // hexadecimal
+ if (preg_match('|&#x([0-9A-F]+);|ie', $char, $matches)) {
+ $ord = hexdec($matches[1]);
+
+ // decimal
+ } else if (preg_match('|&#(\d+);|i', $char, $matches)) {
+ $ord = intval($matches[1]);
+
+ // other html entity
+ } else if (preg_match('|&[^;]+;|', $char, $matches)) {
+ $char = html_entity_decode($matches[0]);
+ $ord = empty($char) ? 0 : ord($char);
+
+ // not an html entity
+ } else {
+ $char = trim($char);
+ $ord = empty($char) ? 0 : ord($char);
+ }
+
+ // lowercase letters (plain or accented)
+ if (($ord>=97 && $ord<=122) || ($ord>=224 && $ord<=255)) {
+ $sort_value = ($ord-31).'.'.sprintf('%04d', $ord);
+
+ // all other characters
+ } else {
+ $sort_value = $ord;
+ }
+
+ return $sort_value;
+}
+
+?>
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:44 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `journal`\r
-#\r
-\r
-CREATE TABLE prefix_journal (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- course int(10) unsigned NOT NULL default '0',\r
- name varchar(255) NOT NULL default '',\r
- intro text NOT NULL default '',\r
- introformat tinyint(2) NOT NULL default '0',\r
- days smallint(5) unsigned NOT NULL default '7',\r
- assessed int(10) NOT NULL default '0',\r
- timemodified int(10) unsigned NOT NULL default '0',\r
- PRIMARY KEY (id),\r
- KEY course (course)\r
-) TYPE=MyISAM;\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `journal_entries`\r
-#\r
-\r
-CREATE TABLE prefix_journal_entries (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- journal int(10) unsigned NOT NULL default '0',\r
- userid int(10) unsigned NOT NULL default '0',\r
- modified int(10) unsigned NOT NULL default '0',\r
- text text NOT NULL default '',\r
- format tinyint(2) NOT NULL default '0',\r
- rating int(10) default '0',\r
- comment text default '',\r
- teacher int(10) unsigned NOT NULL default '0',\r
- timemarked int(10) unsigned NOT NULL default '0',\r
- mailed int(1) unsigned NOT NULL default '0',\r
- PRIMARY KEY (id), \r
- KEY journal (journal),\r
- KEY userid (userid)\r
-) TYPE=MyISAM COMMENT='All the journal entries of all people';\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:44 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `journal`
+#
+
+CREATE TABLE prefix_journal (
+ id int(10) unsigned NOT NULL auto_increment,
+ course int(10) unsigned NOT NULL default '0',
+ name varchar(255) NOT NULL default '',
+ intro text NOT NULL default '',
+ introformat tinyint(2) NOT NULL default '0',
+ days smallint(5) unsigned NOT NULL default '7',
+ assessed int(10) NOT NULL default '0',
+ timemodified int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (id),
+ KEY course (course)
+) TYPE=MyISAM;
+# --------------------------------------------------------
+
+#
+# Table structure for table `journal_entries`
+#
+
+CREATE TABLE prefix_journal_entries (
+ id int(10) unsigned NOT NULL auto_increment,
+ journal int(10) unsigned NOT NULL default '0',
+ userid int(10) unsigned NOT NULL default '0',
+ modified int(10) unsigned NOT NULL default '0',
+ text text NOT NULL default '',
+ format tinyint(2) NOT NULL default '0',
+ rating int(10) default '0',
+ comment text default '',
+ teacher int(10) unsigned NOT NULL default '0',
+ timemarked int(10) unsigned NOT NULL default '0',
+ mailed int(1) unsigned NOT NULL default '0',
+ PRIMARY KEY (id),
+ KEY journal (journal),
+ KEY userid (userid)
+) TYPE=MyISAM COMMENT='All the journal entries of all people';
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');
-rem\r
-rem Table structure for table journal\r
-rem\r
-\r
-drop TABLE prefix_journal;\r
-CREATE TABLE prefix_journal (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- name varchar(255) default NULL,\r
- intro varchar2(1024),\r
- days number(5) default '7' not null,\r
- assessed number(10) default '0' not null,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-drop sequence p_journal_seq;\r
-create sequence p_journal_seq;\r
-\r
-create or replace trigger p_journal_trig\r
- before insert on prefix_journal\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_journal_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(1,'1','1',1,1,1);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(2,'2','2',2,2,2);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(3,'3','3',3,3,3);\r
-insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(4,'4','4',4,4,4);\r
-\r
-select * from prefix_journal order by 1,2;\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table journal_entries\r
-rem\r
-\r
-drop TABLE prefix_journal_entries;\r
-CREATE TABLE prefix_journal_entries (\r
- id number(10) primary key,\r
- journal number(10) default '0' not null,\r
- userid number(10) default '0' not null,\r
- modified number(10) default '0' not null,\r
- text varchar2(1024) NOT NULL,\r
- format number(2) default '0' not null,\r
- rating number(10) default '0',\r
- commentt varchar2(1024),\r
- teacher number(10) default '0' not null,\r
- timemarked number(10) default '0' not null,\r
- mailed number(1) default '0' not null\r
-);\r
-\r
-comment on table prefix_journal_entries is 'All the journal entries of all people';\r
-\r
-drop sequence p_journal_entries_seq;\r
-create sequence p_journal_entries_seq;\r
-\r
-create or replace trigger p_journal_entries_trig\r
- before insert on prefix_journal_entries\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_journal_entries_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(1,1,1,'1',1,1,'1',1,1,1);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(2,2,2,'2',2,2,'2',2,2,2);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(3,3,3,'3',3,3,'3',3,3,3);\r
-insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(4,4,4,'4',4,4,'4',4,4,4);\r
-\r
-select * from prefix_journal_entries order by 1,2;\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-delete from prefix_log_display where module = 'journal';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');\r
-\r
-col module format a10\r
-select * from prefix_log_display where module = 'journal';\r
+rem
+rem Table structure for table journal
+rem
+
+drop TABLE prefix_journal;
+CREATE TABLE prefix_journal (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ name varchar(255) default NULL,
+ intro varchar2(1024),
+ days number(5) default '7' not null,
+ assessed number(10) default '0' not null,
+ timemodified number(10) default '0' not null
+);
+
+drop sequence p_journal_seq;
+create sequence p_journal_seq;
+
+create or replace trigger p_journal_trig
+ before insert on prefix_journal
+ referencing new as new_row
+ for each row
+ begin
+ select p_journal_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(1,'1','1',1,1,1);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(2,'2','2',2,2,2);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(3,'3','3',3,3,3);
+insert into prefix_journal(course,name,intro,days,assessed,timemodified) values(4,'4','4',4,4,4);
+
+select * from prefix_journal order by 1,2;
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table journal_entries
+rem
+
+drop TABLE prefix_journal_entries;
+CREATE TABLE prefix_journal_entries (
+ id number(10) primary key,
+ journal number(10) default '0' not null,
+ userid number(10) default '0' not null,
+ modified number(10) default '0' not null,
+ text varchar2(1024) NOT NULL,
+ format number(2) default '0' not null,
+ rating number(10) default '0',
+ commentt varchar2(1024),
+ teacher number(10) default '0' not null,
+ timemarked number(10) default '0' not null,
+ mailed number(1) default '0' not null
+);
+
+comment on table prefix_journal_entries is 'All the journal entries of all people';
+
+drop sequence p_journal_entries_seq;
+create sequence p_journal_entries_seq;
+
+create or replace trigger p_journal_entries_trig
+ before insert on prefix_journal_entries
+ referencing new as new_row
+ for each row
+ begin
+ select p_journal_entries_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(1,1,1,'1',1,1,'1',1,1,1);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(2,2,2,'2',2,2,'2',2,2,2);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(3,3,3,'3',3,3,'3',3,3,3);
+insert into prefix_journal_entries(journal,userid,modified,text,format,rating,commentt,teacher,timemarked,mailed) values(4,4,4,'4',4,4,'4',4,4,4);
+
+select * from prefix_journal_entries order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+delete from prefix_log_display where module = 'journal';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'add entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'update entry', 'journal', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('journal', 'view responses', 'journal', 'name');
+
+col module format a10
+select * from prefix_log_display where module = 'journal';
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:43 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `resource`\r
-#\r
-\r
-CREATE TABLE prefix_resource (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- course int(10) unsigned NOT NULL default '0',\r
- name varchar(255) NOT NULL default '',\r
- type varchar(30) NOT NULL default '',\r
- reference varchar(255) NOT NULL default '',\r
- summary text NOT NULL default '',\r
- alltext text NOT NULL default '',\r
- popup text NOT NULL default '',\r
- options varchar(255) NOT NULL default '',\r
- timemodified int(10) unsigned NOT NULL default '0',\r
- PRIMARY KEY (id),\r
- UNIQUE KEY id (id),\r
- KEY `course` (`course`)\r
-) TYPE=MyISAM;\r
-\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'update', 'resource', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'add', 'resource', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:43 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `resource`
+#
+
+CREATE TABLE prefix_resource (
+ id int(10) unsigned NOT NULL auto_increment,
+ course int(10) unsigned NOT NULL default '0',
+ name varchar(255) NOT NULL default '',
+ type varchar(30) NOT NULL default '',
+ reference varchar(255) NOT NULL default '',
+ summary text NOT NULL default '',
+ alltext text NOT NULL default '',
+ popup text NOT NULL default '',
+ options varchar(255) NOT NULL default '',
+ timemodified int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (id),
+ UNIQUE KEY id (id),
+ KEY `course` (`course`)
+) TYPE=MyISAM;
+
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'update', 'resource', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'add', 'resource', 'name');
-rem\r
-rem Table structure for table resource\r
-rem\r
-\r
-drop TABLE prefix_resource;\r
-CREATE TABLE prefix_resource (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- name varchar2(255) default '' not null,\r
- type number(4) default '0' not null,\r
- reference varchar2(255) default NULL,\r
- summary varchar2(1024) NOT NULL,\r
- alltext varchar2(1024) NOT NULL,\r
- timemodified number(10) default '0' not null\r
-);\r
-\r
-drop sequence p_resource_seq;\r
-create sequence p_resource_seq;\r
-\r
-create or replace trigger p_resource_trig\r
- before insert on prefix_resource\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_resource_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-comment on table prefix_resource is 'table of resources';\r
-\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(1,'1',1,1,'1','1',1);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(2,'2',2,2,'2','2',2);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(3,'3',3,3,'3','3',3);\r
-insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(4,'4',4,4,'4','4',4);\r
-\r
-select * from prefix_resource order by 1,2;\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-\r
-delete from prefix_log_display where module = 'resource';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');\r
-select * from prefix_log_display where module = 'resource';\r
+rem
+rem Table structure for table resource
+rem
+
+drop TABLE prefix_resource;
+CREATE TABLE prefix_resource (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ name varchar2(255) default '' not null,
+ type number(4) default '0' not null,
+ reference varchar2(255) default NULL,
+ summary varchar2(1024) NOT NULL,
+ alltext varchar2(1024) NOT NULL,
+ timemodified number(10) default '0' not null
+);
+
+drop sequence p_resource_seq;
+create sequence p_resource_seq;
+
+create or replace trigger p_resource_trig
+ before insert on prefix_resource
+ referencing new as new_row
+ for each row
+ begin
+ select p_resource_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+comment on table prefix_resource is 'table of resources';
+
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(1,'1',1,1,'1','1',1);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(2,'2',2,2,'2','2',2);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(3,'3',3,3,'3','3',3);
+insert into prefix_resource(course,name,type,reference,summary,alltext,timemodified) values(4,'4',4,4,'4','4',4);
+
+select * from prefix_resource order by 1,2;
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'resource';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('resource', 'view', 'resource', 'name');
+select * from prefix_log_display where module = 'resource';
-<php\r
- require_once('../../config.php');\r
- require_once('locallib.php');\r
- \r
- $command = required_param('command', PARAM_ALPHA);\r
- $sessionid = required_param('session_id', PARAM_ALPHANUM);\r
- $aiccdata = optional_param('aicc_data', '', PARAM_RAW);\r
-\r
- require_login();\r
- \r
- if (!empty($command) && confirm_sesskey($sessionid)) {\r
- $command = strtolower($command);\r
- \r
- if (isset($SESSION->scorm_scoid)) {\r
- $scoid = $SESSION->scorm_scoid;\r
- } else {\r
- error('Invalid script call');\r
- }\r
- $mode = 'normal';\r
- if (isset($SESSION->scorm_mode)) {\r
- $mode = $SESSION->scorm_mode;\r
- }\r
- $status = 'Not Initialized';\r
- if (isset($SESSION->scorm_status)) {\r
- $status = $SESSION->scorm_status;\r
- }\r
- if (isset($SESSION->attempt)) {\r
- $attempt = $SESSION->attempt;\r
- } else {\r
- $attempt = 1;\r
- }\r
-\r
- if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
- if (!$scorm = get_record('scorm','id',$sco->scorm)) {\r
- error('Invalid script call');\r
- }\r
- } else {\r
- error('Invalid script call');\r
- }\r
-\r
- if ($scorm = get_record('scorm','id',$sco->scorm)) {\r
- switch ($command) {\r
- case 'getparam':\r
- if ($status == 'Not Initialized') {\r
- $SESSION->scorm_status = 'Running';\r
- $status = 'Running';\r
- }\r
- if ($status != 'Running') {\r
- echo "error = 101\nerror_text = Terminated\n";\r
- } else {\r
- if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {\r
- $userdata = $usertrack;\r
- } else {\r
- $userdata->status = '';\r
- $userdata->score_raw = '';\r
- }\r
- $userdata->student_id = $USER->username;\r
- $userdata->student_name = $USER->lastname .', '. $USER->firstname;\r
- $userdata->mode = $mode;\r
- if ($userdata->mode == 'normal') {\r
- $userdata->credit = 'credit';\r
- } else {\r
- $userdata->credit = 'no-credit';\r
- } \r
- \r
- if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
- $userdata->course_id = $sco->identifier;\r
- $userdata->datafromlms = $sco->datafromlms;\r
- $userdata->masteryscore = $sco->masteryscore;\r
- $userdata->maxtimeallowed = $sco->maxtimeallowed;\r
- $userdata->timelimitaction = $sco->timelimitaction;\r
- \r
- echo "error = 0\nerror_text = Successful\naicc_data=\n";\r
- echo "[Core]\n";\r
- echo 'Student_ID = '.$userdata->student_id."\n";\r
- echo 'Student_Name = '.$userdata->student_name."\n";\r
- if (isset($userdata->{'cmi.core.lesson_location'})) {\r
- echo 'Lesson_Location = '.$userdata->{'cmi.core.lesson_location'}."\n";\r
- } else {\r
- echo 'Lesson_Location = '."\n";\r
- }\r
- echo 'Credit = '.$userdata->credit."\n";\r
- if (isset($userdata->status)) {\r
- if ($userdata->status == '') {\r
- $userdata->entry = ', ab-initio';\r
- } else {\r
- if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {\r
- $userdata->entry = ', resume';\r
- } else {\r
- $userdata->entry = '';\r
- }\r
- }\r
- }\r
- if (isset($userdata->{'cmi.core.lesson_status'})) {\r
- echo 'Lesson_Status = '.$userdata->{'cmi.core.lesson_status'}.$userdata->entry."\n";\r
- $SESSION->scorm_lessonstatus = $userdata->{'cmi.core.lesson_status'};\r
- } else {\r
- echo 'Lesson_Status = not attempted'.$userdata->entry."\n";\r
- $SESSION->scorm_lessonstatus = 'not attempted';\r
- }\r
- if (isset($userdata->{'cmi.core.score.raw'})) {\r
- $max = '';\r
- $min = '';\r
- if (isset($userdata->{'cmi.core.score.max'}) && !empty($userdata->{'cmi.core.score.max'})) {\r
- $max = ', '.$userdata->{'cmi.core.score.max'};\r
- if (isset($userdata->{'cmi.core.score.min'}) && !empty($userdata->{'cmi.core.score.min'})) {\r
- $min = ', '.$userdata->{'cmi.core.score.min'};\r
- }\r
- }\r
- echo 'Score = '.$userdata->{'cmi.core.score.raw'}.$max.$min."\n";\r
- } else {\r
- echo 'Score = '."\n";\r
- }\r
- if (isset($userdata->{'cmi.core.total_time'})) {\r
- echo 'Time = '.$userdata->{'cmi.core.total_time'}."\n";\r
- } else {\r
- echo 'Time = '.'00:00:00'."\n";\r
- }\r
- echo 'Lesson_Mode = '.$userdata->mode."\n";\r
- if (isset($userdata->{'cmi.suspend_data'})) {\r
- echo "[Core_Lesson]\n".$userdata->{'cmi.suspend_data'}."\n";\r
- } else {\r
- echo "[Core_Lesson]\n"."\n";\r
- }\r
- echo "[Core_Vendor]\n".$userdata->datafromlms."\n";\r
- echo "[Evaluation]\nCourse_ID = {".$userdata->course_id."}\n";\r
- echo "[Student_Data]\n";\r
- echo 'Mastery_Score = '.$userdata->masteryscore."\n";\r
- echo 'Max_Time_Allowed = '.$userdata->maxtimeallowed."\n";\r
- echo 'Time_Limit_Action = '.$userdata->timelimitaction."\n";\r
- } else {\r
- error('Sco not found');\r
- }\r
- }\r
- break;\r
- case 'putparam':\r
- if ($status == 'Running') {\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $scorm->course)) {\r
- echo "error = 1\nerror_text = Unknown\n"; // No one must see this error message if not hacked\r
- }\r
- if (!empty($aiccdata) && has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) {\r
- $initlessonstatus = 'not attempted';\r
- $lessonstatus = 'not attempted';\r
- if (isset($SESSION->scorm_lessonstatus)) {\r
- $initlessonstatus = $SESSION->scorm_lessonstatus;\r
- }\r
- $score = '';\r
- $datamodel['lesson_location'] = 'cmi.core.lesson_location';\r
- $datamodel['lesson_status'] = 'cmi.core.lesson_status';\r
- $datamodel['score'] = 'cmi.core.score.raw';\r
- $datamodel['time'] = 'cmi.core.session_time';\r
- $datamodel['[core_lesson]'] = 'cmi.suspend_data';\r
- $datamodel['[comments]'] = 'cmi.comments';\r
- $datarows = explode("\n",$aiccdata);\r
- reset($datarows);\r
- while ((list(,$datarow) = each($datarows)) !== false) {\r
- if (($equal = strpos($datarow, '=')) !== false) {\r
- $element = strtolower(trim(substr($datarow,0,$equal)));\r
- $value = trim(substr($datarow,$equal+1));\r
- if (isset($datamodel[$element])) {\r
- $element = $datamodel[$element];\r
- switch ($element) {\r
- case 'cmi.core.lesson_location':\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
- break;\r
- case 'cmi.core.lesson_status':\r
- $statuses = array(\r
- 'passed' => 'passed',\r
- 'completed' => 'completed',\r
- 'failed' => 'failed',\r
- 'incomplete' => 'incomplete',\r
- 'browsed' => 'browsed',\r
- 'not attempted' => 'not attempted',\r
- 'p' => 'passed',\r
- 'c' => 'completed',\r
- 'f' => 'failed',\r
- 'i' => 'incomplete',\r
- 'b' => 'browsed',\r
- 'n' => 'not attempted'\r
- );\r
- $exites = array(\r
- 'logout' => 'logout',\r
- 'time-out' => 'time-out',\r
- 'suspend' => 'suspend',\r
- 'l' => 'logout',\r
- 't' => 'time-out',\r
- 's' => 'suspend',\r
- );\r
- $values = explode(',',$value);\r
- $value = '';\r
- if (count($values) > 1) {\r
- $value = trim(strtolower($values[1]));\r
- if (isset($exites[$value])) {\r
- $value = $exites[$value];\r
- }\r
- }\r
- if (empty($value) || isset($exites[$value])) {\r
- $subelement = 'cmi.core.exit';\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
- }\r
- $value = trim(strtolower($values[0]));\r
- if (isset($statuses[$value]) && ($mode == 'normal')) {\r
- $value = $statuses[$value];\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
- }\r
- $lessonstatus = $value;\r
- break;\r
- case 'cmi.core.score.raw':\r
- $values = explode(',',$value);\r
- if ((count($values) > 1) && ($values[1] >= $values[0]) && is_numeric($values[1])) {\r
- $subelement = 'cmi.core.score.max';\r
- $value = trim($values[1]);\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
- if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {\r
- $subelement = 'cmi.core.score.min';\r
- $value = trim($values[2]);\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);\r
- }\r
- }\r
- \r
- $value = '';\r
- if (is_numeric($values[0])) {\r
- $value = trim($values[0]);\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
- }\r
- $score = $value;\r
- break;\r
- case 'cmi.core.session_time':\r
- $SESSION->scorm_session_time = $value;\r
- break;\r
- }\r
- }\r
- } else {\r
- if (isset($datamodel[strtolower(trim($datarow))])) {\r
- $element = $datamodel[strtolower(trim($datarow))];\r
- $value = '';\r
- while ((($datarow = current($datarows)) !== false) && (substr($datarow,0,1) != '[')) {\r
- $value .= $datarow;\r
- next($datarows);\r
- }\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);\r
- }\r
- } \r
- }\r
- if (($mode == 'browse') && ($initlessonstatus == 'not attempted')){\r
- $lessonstatus = 'browsed';\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed');\r
- }\r
- if ($mode == 'normal') {\r
- if ($lessonstatus == 'completed') {\r
- if (!empty($sco->masteryscore) && !empty($score) && ($score >= $sco->masteryscore)) {\r
- $lessonstatus = 'passed';\r
- } else {\r
- $lessonstatus = 'failed';\r
- }\r
- $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus);\r
- }\r
- } \r
- }\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'putcomments':\r
- if ($status == 'Running') {\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'putinteractions':\r
- if ($status == 'Running') {\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'putobjectives':\r
- if ($status == 'Running') {\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'putpath':\r
- if ($status == 'Running') {\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'putperformance':\r
- if ($status == 'Running') {\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- case 'exitau':\r
- if ($status == 'Running') {\r
- if (isset($SESSION->scorm_session_time) && ($SESSION->scorm_session_time != '')) {\r
- if ($track = get_record_select('scorm_scoes_track',"userid='$USER->id' AND scormid='$scorm->id' AND scoid='$sco->id' AND element='cmi.core.total_time'")) {\r
- // Add session_time to total_time\r
- $value = scorm_add_time($track->value, $SESSION->scorm_session_time);\r
- $track->value = $value;\r
- $track->timemodified = time();\r
- $id = update_record('scorm_scoes_track',$track);\r
- } else {\r
- $track->userid = $USER->id;\r
- $track->scormid = $scorm->id;\r
- $track->scoid = $sco->id;\r
- $track->element = 'cmi.core.total_time';\r
- $track->value = $SESSION->scorm_session_time;\r
- $track->timemodified = time();\r
- $id = insert_record('scorm_scoes_track',$track);\r
- }\r
- }\r
- \r
- $SESSION->scorm_status = 'Terminated';\r
- $SESSION->scorm_session_time = '';\r
- echo "error = 0\nerror_text = Successful\n";\r
- } else if ($status == 'Terminated') {\r
- echo "error = 1\nerror_text = Terminated\n";\r
- } else {\r
- echo "error = 1\nerror_text = Not Initialized\n";\r
- }\r
- break;\r
- default:\r
- echo "error = 1\nerror_text = Invalid Command\n";\r
- break;\r
- }\r
- }\r
- } else {\r
- if (empty($command)) {\r
- echo "error = 1\nerror_text = Invalid Command\n";\r
- } else {\r
- echo "error = 3\nerror_text = Invalid Session ID\n";\r
- }\r
- }\r
-?>\r
+<php
+ require_once('../../config.php');
+ require_once('locallib.php');
+
+ $command = required_param('command', PARAM_ALPHA);
+ $sessionid = required_param('session_id', PARAM_ALPHANUM);
+ $aiccdata = optional_param('aicc_data', '', PARAM_RAW);
+
+ require_login();
+
+ if (!empty($command) && confirm_sesskey($sessionid)) {
+ $command = strtolower($command);
+
+ if (isset($SESSION->scorm_scoid)) {
+ $scoid = $SESSION->scorm_scoid;
+ } else {
+ error('Invalid script call');
+ }
+ $mode = 'normal';
+ if (isset($SESSION->scorm_mode)) {
+ $mode = $SESSION->scorm_mode;
+ }
+ $status = 'Not Initialized';
+ if (isset($SESSION->scorm_status)) {
+ $status = $SESSION->scorm_status;
+ }
+ if (isset($SESSION->attempt)) {
+ $attempt = $SESSION->attempt;
+ } else {
+ $attempt = 1;
+ }
+
+ if ($sco = get_record('scorm_scoes','id',$scoid)) {
+ if (!$scorm = get_record('scorm','id',$sco->scorm)) {
+ error('Invalid script call');
+ }
+ } else {
+ error('Invalid script call');
+ }
+
+ if ($scorm = get_record('scorm','id',$sco->scorm)) {
+ switch ($command) {
+ case 'getparam':
+ if ($status == 'Not Initialized') {
+ $SESSION->scorm_status = 'Running';
+ $status = 'Running';
+ }
+ if ($status != 'Running') {
+ echo "error = 101\nerror_text = Terminated\n";
+ } else {
+ if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {
+ $userdata = $usertrack;
+ } else {
+ $userdata->status = '';
+ $userdata->score_raw = '';
+ }
+ $userdata->student_id = $USER->username;
+ $userdata->student_name = $USER->lastname .', '. $USER->firstname;
+ $userdata->mode = $mode;
+ if ($userdata->mode == 'normal') {
+ $userdata->credit = 'credit';
+ } else {
+ $userdata->credit = 'no-credit';
+ }
+
+ if ($sco = get_record('scorm_scoes','id',$scoid)) {
+ $userdata->course_id = $sco->identifier;
+ $userdata->datafromlms = $sco->datafromlms;
+ $userdata->masteryscore = $sco->masteryscore;
+ $userdata->maxtimeallowed = $sco->maxtimeallowed;
+ $userdata->timelimitaction = $sco->timelimitaction;
+
+ echo "error = 0\nerror_text = Successful\naicc_data=\n";
+ echo "[Core]\n";
+ echo 'Student_ID = '.$userdata->student_id."\n";
+ echo 'Student_Name = '.$userdata->student_name."\n";
+ if (isset($userdata->{'cmi.core.lesson_location'})) {
+ echo 'Lesson_Location = '.$userdata->{'cmi.core.lesson_location'}."\n";
+ } else {
+ echo 'Lesson_Location = '."\n";
+ }
+ echo 'Credit = '.$userdata->credit."\n";
+ if (isset($userdata->status)) {
+ if ($userdata->status == '') {
+ $userdata->entry = ', ab-initio';
+ } else {
+ if (isset($userdata->{'cmi.core.exit'}) && ($userdata->{'cmi.core.exit'} == 'suspend')) {
+ $userdata->entry = ', resume';
+ } else {
+ $userdata->entry = '';
+ }
+ }
+ }
+ if (isset($userdata->{'cmi.core.lesson_status'})) {
+ echo 'Lesson_Status = '.$userdata->{'cmi.core.lesson_status'}.$userdata->entry."\n";
+ $SESSION->scorm_lessonstatus = $userdata->{'cmi.core.lesson_status'};
+ } else {
+ echo 'Lesson_Status = not attempted'.$userdata->entry."\n";
+ $SESSION->scorm_lessonstatus = 'not attempted';
+ }
+ if (isset($userdata->{'cmi.core.score.raw'})) {
+ $max = '';
+ $min = '';
+ if (isset($userdata->{'cmi.core.score.max'}) && !empty($userdata->{'cmi.core.score.max'})) {
+ $max = ', '.$userdata->{'cmi.core.score.max'};
+ if (isset($userdata->{'cmi.core.score.min'}) && !empty($userdata->{'cmi.core.score.min'})) {
+ $min = ', '.$userdata->{'cmi.core.score.min'};
+ }
+ }
+ echo 'Score = '.$userdata->{'cmi.core.score.raw'}.$max.$min."\n";
+ } else {
+ echo 'Score = '."\n";
+ }
+ if (isset($userdata->{'cmi.core.total_time'})) {
+ echo 'Time = '.$userdata->{'cmi.core.total_time'}."\n";
+ } else {
+ echo 'Time = '.'00:00:00'."\n";
+ }
+ echo 'Lesson_Mode = '.$userdata->mode."\n";
+ if (isset($userdata->{'cmi.suspend_data'})) {
+ echo "[Core_Lesson]\n".$userdata->{'cmi.suspend_data'}."\n";
+ } else {
+ echo "[Core_Lesson]\n"."\n";
+ }
+ echo "[Core_Vendor]\n".$userdata->datafromlms."\n";
+ echo "[Evaluation]\nCourse_ID = {".$userdata->course_id."}\n";
+ echo "[Student_Data]\n";
+ echo 'Mastery_Score = '.$userdata->masteryscore."\n";
+ echo 'Max_Time_Allowed = '.$userdata->maxtimeallowed."\n";
+ echo 'Time_Limit_Action = '.$userdata->timelimitaction."\n";
+ } else {
+ error('Sco not found');
+ }
+ }
+ break;
+ case 'putparam':
+ if ($status == 'Running') {
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $scorm->course)) {
+ echo "error = 1\nerror_text = Unknown\n"; // No one must see this error message if not hacked
+ }
+ if (!empty($aiccdata) && has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE, $cm->id))) {
+ $initlessonstatus = 'not attempted';
+ $lessonstatus = 'not attempted';
+ if (isset($SESSION->scorm_lessonstatus)) {
+ $initlessonstatus = $SESSION->scorm_lessonstatus;
+ }
+ $score = '';
+ $datamodel['lesson_location'] = 'cmi.core.lesson_location';
+ $datamodel['lesson_status'] = 'cmi.core.lesson_status';
+ $datamodel['score'] = 'cmi.core.score.raw';
+ $datamodel['time'] = 'cmi.core.session_time';
+ $datamodel['[core_lesson]'] = 'cmi.suspend_data';
+ $datamodel['[comments]'] = 'cmi.comments';
+ $datarows = explode("\n",$aiccdata);
+ reset($datarows);
+ while ((list(,$datarow) = each($datarows)) !== false) {
+ if (($equal = strpos($datarow, '=')) !== false) {
+ $element = strtolower(trim(substr($datarow,0,$equal)));
+ $value = trim(substr($datarow,$equal+1));
+ if (isset($datamodel[$element])) {
+ $element = $datamodel[$element];
+ switch ($element) {
+ case 'cmi.core.lesson_location':
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+ break;
+ case 'cmi.core.lesson_status':
+ $statuses = array(
+ 'passed' => 'passed',
+ 'completed' => 'completed',
+ 'failed' => 'failed',
+ 'incomplete' => 'incomplete',
+ 'browsed' => 'browsed',
+ 'not attempted' => 'not attempted',
+ 'p' => 'passed',
+ 'c' => 'completed',
+ 'f' => 'failed',
+ 'i' => 'incomplete',
+ 'b' => 'browsed',
+ 'n' => 'not attempted'
+ );
+ $exites = array(
+ 'logout' => 'logout',
+ 'time-out' => 'time-out',
+ 'suspend' => 'suspend',
+ 'l' => 'logout',
+ 't' => 'time-out',
+ 's' => 'suspend',
+ );
+ $values = explode(',',$value);
+ $value = '';
+ if (count($values) > 1) {
+ $value = trim(strtolower($values[1]));
+ if (isset($exites[$value])) {
+ $value = $exites[$value];
+ }
+ }
+ if (empty($value) || isset($exites[$value])) {
+ $subelement = 'cmi.core.exit';
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+ }
+ $value = trim(strtolower($values[0]));
+ if (isset($statuses[$value]) && ($mode == 'normal')) {
+ $value = $statuses[$value];
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+ }
+ $lessonstatus = $value;
+ break;
+ case 'cmi.core.score.raw':
+ $values = explode(',',$value);
+ if ((count($values) > 1) && ($values[1] >= $values[0]) && is_numeric($values[1])) {
+ $subelement = 'cmi.core.score.max';
+ $value = trim($values[1]);
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+ if ((count($values) == 3) && ($values[2] <= $values[0]) && is_numeric($values[2])) {
+ $subelement = 'cmi.core.score.min';
+ $value = trim($values[2]);
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $subelement, $value);
+ }
+ }
+
+ $value = '';
+ if (is_numeric($values[0])) {
+ $value = trim($values[0]);
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+ }
+ $score = $value;
+ break;
+ case 'cmi.core.session_time':
+ $SESSION->scorm_session_time = $value;
+ break;
+ }
+ }
+ } else {
+ if (isset($datamodel[strtolower(trim($datarow))])) {
+ $element = $datamodel[strtolower(trim($datarow))];
+ $value = '';
+ while ((($datarow = current($datarows)) !== false) && (substr($datarow,0,1) != '[')) {
+ $value .= $datarow;
+ next($datarows);
+ }
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, $element, $value);
+ }
+ }
+ }
+ if (($mode == 'browse') && ($initlessonstatus == 'not attempted')){
+ $lessonstatus = 'browsed';
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', 'browsed');
+ }
+ if ($mode == 'normal') {
+ if ($lessonstatus == 'completed') {
+ if (!empty($sco->masteryscore) && !empty($score) && ($score >= $sco->masteryscore)) {
+ $lessonstatus = 'passed';
+ } else {
+ $lessonstatus = 'failed';
+ }
+ $id = scorm_insert_track($USER->id, $scorm->id, $sco->id, $attempt, 'cmi.core.lesson_status', $lessonstatus);
+ }
+ }
+ }
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'putcomments':
+ if ($status == 'Running') {
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'putinteractions':
+ if ($status == 'Running') {
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'putobjectives':
+ if ($status == 'Running') {
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'putpath':
+ if ($status == 'Running') {
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'putperformance':
+ if ($status == 'Running') {
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ case 'exitau':
+ if ($status == 'Running') {
+ if (isset($SESSION->scorm_session_time) && ($SESSION->scorm_session_time != '')) {
+ if ($track = get_record_select('scorm_scoes_track',"userid='$USER->id' AND scormid='$scorm->id' AND scoid='$sco->id' AND element='cmi.core.total_time'")) {
+ // Add session_time to total_time
+ $value = scorm_add_time($track->value, $SESSION->scorm_session_time);
+ $track->value = $value;
+ $track->timemodified = time();
+ $id = update_record('scorm_scoes_track',$track);
+ } else {
+ $track->userid = $USER->id;
+ $track->scormid = $scorm->id;
+ $track->scoid = $sco->id;
+ $track->element = 'cmi.core.total_time';
+ $track->value = $SESSION->scorm_session_time;
+ $track->timemodified = time();
+ $id = insert_record('scorm_scoes_track',$track);
+ }
+ }
+
+ $SESSION->scorm_status = 'Terminated';
+ $SESSION->scorm_session_time = '';
+ echo "error = 0\nerror_text = Successful\n";
+ } else if ($status == 'Terminated') {
+ echo "error = 1\nerror_text = Terminated\n";
+ } else {
+ echo "error = 1\nerror_text = Not Initialized\n";
+ }
+ break;
+ default:
+ echo "error = 1\nerror_text = Invalid Command\n";
+ break;
+ }
+ }
+ } else {
+ if (empty($command)) {
+ echo "error = 1\nerror_text = Invalid Command\n";
+ } else {
+ echo "error = 3\nerror_text = Invalid Session ID\n";
+ }
+ }
+?>
-<?php\r
-\r
- require_once("../../config.php");\r
- require_once('locallib.php');\r
- \r
- $id = optional_param('id', '', PARAM_INT); // Course Module ID, or\r
- $a = optional_param('a', '', PARAM_INT); // scorm ID\r
- $scoid = required_param('scoid', PARAM_INT); // sco ID\r
- $mode = optional_param('mode', '', PARAM_ALPHA); // navigation mode\r
- $attempt = required_param('attempt', PARAM_INT); // new attempt\r
-\r
- if (!empty($id)) {\r
- if (! $cm = get_coursemodule_from_id('scorm', $id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $cm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
- error("Course module is incorrect");\r
- }\r
- } else if (!empty($a)) {\r
- if (! $scorm = get_record("scorm", "id", $a)) {\r
- error("Course module is incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $scorm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- } else {\r
- error('A required parameter is missing');\r
- }\r
-\r
- require_login($course->id, false, $cm);\r
- \r
- if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {\r
- $userdata = $usertrack;\r
- } else {\r
- $userdata->status = '';\r
- $userdata->score_raw = '';\r
- }\r
- $userdata->student_id = addslashes($USER->username);\r
- $userdata->student_name = addslashes($USER->lastname .', '. $USER->firstname);\r
- $userdata->mode = 'normal';\r
- if (isset($mode)) {\r
- $userdata->mode = $mode;\r
- }\r
- if ($userdata->mode == 'normal') {\r
- $userdata->credit = 'credit';\r
- } else {\r
- $userdata->credit = 'no-credit';\r
- } \r
- if ($sco = get_record('scorm_scoes','id',$scoid)) {\r
- $userdata->datafromlms = $sco->datafromlms;\r
- $userdata->masteryscore = $sco->masteryscore;\r
- $userdata->maxtimeallowed = $sco->maxtimeallowed;\r
- $userdata->timelimitaction = $sco->timelimitaction;\r
- } else {\r
- error('Sco not found');\r
- }\r
- $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe\r
- if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php')) {\r
- include_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php');\r
- } else {\r
- include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.js.php');\r
- }\r
-?>\r
-\r
-var errorCode = "0";\r
-function underscore(str) {\r
- return str.replace(/\./g,"__");\r
-}\r
+<?php
+
+ require_once("../../config.php");
+ require_once('locallib.php');
+
+ $id = optional_param('id', '', PARAM_INT); // Course Module ID, or
+ $a = optional_param('a', '', PARAM_INT); // scorm ID
+ $scoid = required_param('scoid', PARAM_INT); // sco ID
+ $mode = optional_param('mode', '', PARAM_ALPHA); // navigation mode
+ $attempt = required_param('attempt', PARAM_INT); // new attempt
+
+ if (!empty($id)) {
+ if (! $cm = get_coursemodule_from_id('scorm', $id)) {
+ error("Course Module ID was incorrect");
+ }
+ if (! $course = get_record("course", "id", $cm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+ } else if (!empty($a)) {
+ if (! $scorm = get_record("scorm", "id", $a)) {
+ error("Course module is incorrect");
+ }
+ if (! $course = get_record("course", "id", $scorm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+ error("Course Module ID was incorrect");
+ }
+ } else {
+ error('A required parameter is missing');
+ }
+
+ require_login($course->id, false, $cm);
+
+ if ($usertrack=scorm_get_tracks($scoid,$USER->id,$attempt)) {
+ $userdata = $usertrack;
+ } else {
+ $userdata->status = '';
+ $userdata->score_raw = '';
+ }
+ $userdata->student_id = addslashes($USER->username);
+ $userdata->student_name = addslashes($USER->lastname .', '. $USER->firstname);
+ $userdata->mode = 'normal';
+ if (isset($mode)) {
+ $userdata->mode = $mode;
+ }
+ if ($userdata->mode == 'normal') {
+ $userdata->credit = 'credit';
+ } else {
+ $userdata->credit = 'no-credit';
+ }
+ if ($sco = get_record('scorm_scoes','id',$scoid)) {
+ $userdata->datafromlms = $sco->datafromlms;
+ $userdata->masteryscore = $sco->masteryscore;
+ $userdata->maxtimeallowed = $sco->maxtimeallowed;
+ $userdata->timelimitaction = $sco->timelimitaction;
+ } else {
+ error('Sco not found');
+ }
+ $scorm->version = strtolower(clean_param($scorm->version, PARAM_SAFEDIR)); // Just to be safe
+ if (file_exists($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php')) {
+ include_once($CFG->dirroot.'/mod/scorm/datamodels/'.$scorm->version.'.js.php');
+ } else {
+ include_once($CFG->dirroot.'/mod/scorm/datamodels/scorm_12.js.php');
+ }
+?>
+
+var errorCode = "0";
+function underscore(str) {
+ return str.replace(/\./g,"__");
+}
-<?php // $Id$\r
-\r
- require_once("../../config.php");\r
- require_once('locallib.php');\r
- \r
- $id = optional_param('id', '', PARAM_INT); // Course Module ID, or\r
- $a = optional_param('a', '', PARAM_INT); // SCORM ID\r
- $b = optional_param('b', '', PARAM_INT); // SCO ID\r
- $user = optional_param('user', '', PARAM_INT); // User ID\r
-\r
- if (!empty($id)) {\r
- if (! $cm = get_record("course_modules", "id", $id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $cm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
- error("Course module is incorrect");\r
- }\r
- } else {\r
- if (!empty($b)) {\r
- if (! $sco = get_record("scorm_scoes", "id", $b)) {\r
- error("Scorm activity is incorrect");\r
- }\r
- $a = $sco->scorm;\r
- }\r
- if (!empty($a)) {\r
- if (! $scorm = get_record("scorm", "id", $a)) {\r
- error("Course module is incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $scorm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- }\r
- }\r
-\r
- require_login($course->id, false, $cm);\r
- require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));\r
-\r
- add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");\r
-\r
-/// Print the page header\r
- if (empty($noheader)) {\r
- if ($course->category) {\r
- $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";\r
- } else {\r
- $navigation = '';\r
- }\r
-\r
- $strscorms = get_string("modulenameplural", "scorm");\r
- $strscorm = get_string("modulename", "scorm");\r
- $strreport = get_string("report", "scorm");\r
- $strname = get_string('name');\r
- $strcoefficient = get_string('coefficient',"scorm");\r
- $strcoefficient = "Thiet lap he so";\r
- if (empty($b)) {\r
- print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
- "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
- -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",\r
- "", "", true);\r
- } else {\r
- print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
- "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
- -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>\r
- -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",\r
- "", "", true);\r
- }\r
- print_heading(format_string($scorm->name));\r
- }\r
-\r
- $scormpixdir = $CFG->modpixpath.'/scorm/pix';\r
-\r
- //Phan trinh bay chinh\r
-?>\r
-\r
- <?php\r
- $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');\r
- foreach ($examScoes as $examSco){\r
- $newcoefficient = optional_param($examSco->id,'',PARAM_INT);\r
- $sco = get_record('scorm_scoes','scorm',$scorm->id,'id',$examSco->id,'','');\r
- $sco->score_coefficient = $newcoefficient;\r
- $ketqua = update_record('scorm_scoes',$sco);\r
- //echo "Cap nhat $examSco->id voi he so diem ".$newcoefficient."<br>";\r
- }\r
-\r
- if ($ketqua)\r
- {\r
- echo "".get_string('updatesuccess','scorm');\r
- }\r
- else\r
- {\r
- echo "".get_string('updatefail','scorm');\r
- }\r
-\r
- echo "<br><br><a href=coefficientsetting.php?id=$id>".get_string('back','scorm')."</a>"\r
-?>\r
-<?php\r
- //ket thuc phan trinh bay chinh\r
-\r
- if (empty($noheader)) {\r
- print_footer($course);\r
- }\r
-?>\r
+<?php // $Id$
+
+ require_once("../../config.php");
+ require_once('locallib.php');
+
+ $id = optional_param('id', '', PARAM_INT); // Course Module ID, or
+ $a = optional_param('a', '', PARAM_INT); // SCORM ID
+ $b = optional_param('b', '', PARAM_INT); // SCO ID
+ $user = optional_param('user', '', PARAM_INT); // User ID
+
+ if (!empty($id)) {
+ if (! $cm = get_record("course_modules", "id", $id)) {
+ error("Course Module ID was incorrect");
+ }
+ if (! $course = get_record("course", "id", $cm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+ } else {
+ if (!empty($b)) {
+ if (! $sco = get_record("scorm_scoes", "id", $b)) {
+ error("Scorm activity is incorrect");
+ }
+ $a = $sco->scorm;
+ }
+ if (!empty($a)) {
+ if (! $scorm = get_record("scorm", "id", $a)) {
+ error("Course module is incorrect");
+ }
+ if (! $course = get_record("course", "id", $scorm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+ error("Course Module ID was incorrect");
+ }
+ }
+ }
+
+ require_login($course->id, false, $cm);
+ require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));
+
+ add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");
+
+/// Print the page header
+ if (empty($noheader)) {
+ if ($course->category) {
+ $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
+ } else {
+ $navigation = '';
+ }
+
+ $strscorms = get_string("modulenameplural", "scorm");
+ $strscorm = get_string("modulename", "scorm");
+ $strreport = get_string("report", "scorm");
+ $strname = get_string('name');
+ $strcoefficient = get_string('coefficient',"scorm");
+ $strcoefficient = "Thiet lap he so";
+ if (empty($b)) {
+ print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+ "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+ -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",
+ "", "", true);
+ } else {
+ print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+ "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+ -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>
+ -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",
+ "", "", true);
+ }
+ print_heading(format_string($scorm->name));
+ }
+
+ $scormpixdir = $CFG->modpixpath.'/scorm/pix';
+
+ //Phan trinh bay chinh
+?>
+
+ <?php
+ $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');
+ foreach ($examScoes as $examSco){
+ $newcoefficient = optional_param($examSco->id,'',PARAM_INT);
+ $sco = get_record('scorm_scoes','scorm',$scorm->id,'id',$examSco->id,'','');
+ $sco->score_coefficient = $newcoefficient;
+ $ketqua = update_record('scorm_scoes',$sco);
+ //echo "Cap nhat $examSco->id voi he so diem ".$newcoefficient."<br>";
+ }
+
+ if ($ketqua)
+ {
+ echo "".get_string('updatesuccess','scorm');
+ }
+ else
+ {
+ echo "".get_string('updatefail','scorm');
+ }
+
+ echo "<br><br><a href=coefficientsetting.php?id=$id>".get_string('back','scorm')."</a>"
+?>
+<?php
+ //ket thuc phan trinh bay chinh
+
+ if (empty($noheader)) {
+ print_footer($course);
+ }
+?>
-<?php // $Id$\r
-\r
- require_once("../../config.php");\r
- require_once('locallib.php');\r
- \r
- $id = optional_param('id', '', PARAM_INT); // Course Module ID, or\r
- $a = optional_param('a', '', PARAM_INT); // SCORM ID\r
- $b = optional_param('b', '', PARAM_INT); // SCO ID\r
- $user = optional_param('user', '', PARAM_INT); // User ID\r
-\r
- if (!empty($id)) {\r
- if (! $cm = get_record("course_modules", "id", $id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $cm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
- error("Course module is incorrect");\r
- }\r
- } else {\r
- if (!empty($b)) {\r
- if (! $sco = get_record("scorm_scoes", "id", $b)) {\r
- error("Scorm activity is incorrect");\r
- }\r
- $a = $sco->scorm;\r
- }\r
- if (!empty($a)) {\r
- if (! $scorm = get_record("scorm", "id", $a)) {\r
- error("Course module is incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $scorm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- }\r
- }\r
-\r
- require_login($course->id, false, $cm);\r
- require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));\r
-\r
- add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");\r
-\r
-/// Print the page header\r
- if (empty($noheader)) {\r
- if ($course->category) {\r
- $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";\r
- } else {\r
- $navigation = '';\r
- }\r
-\r
- $strscorms = get_string("modulenameplural", "scorm");\r
- $strscorm = get_string("modulename", "scorm");\r
- $strreport = get_string("report", "scorm");\r
- $strname = get_string('name');\r
- $strcoefficient = get_string('coefficient','scorm');\r
- if (empty($b)) {\r
- print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
- "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
- -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",\r
- "", "", true);\r
- } else {\r
- print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",\r
- "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>\r
- -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>\r
- -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",\r
- "", "", true);\r
- }\r
- print_heading(format_string($scorm->name));\r
- }\r
-\r
- $scormpixdir = $CFG->modpixpath.'/scorm/pix';\r
-\r
- //Phan trinh bay chinh\r
-?>\r
-<script type="text/javascript">\r
-function validate_form()\r
-{\r
- return true;\r
-}\r
-</script>\r
-<form name="form" method="post" action="coefficientconfirm.php" onsubmit="return validate_form();" >\r
- <table width="50%" border="0">\r
- <tr>\r
- <td class="scormtableheader"><?php echo(get_string('title','scorm')); ?></td>\r
- <td class="scormtableheader"><?php echo(get_string('coefficient','scorm')); ?></td>\r
- </tr>\r
- \r
- <?php\r
- $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');\r
- if(!empty($examScoes))\r
- {\r
- \r
- foreach ($examScoes as $examSco){\r
- echo "<tr><td>"; \r
- echo "$examSco->identifier.</td><td><input type='text' name='$examSco->id' class='scormtextbox' value=$examSco->score_coefficient /></td></tr><br>";\r
- }\r
- }\r
-\r
-?>\r
- </table>\r
-<br>\r
-<input type="hidden" name="id" value="<?php p($id) ?>" />\r
-<input type="submit" value="<?php print_string('savechanges') ?>" />\r
-</form>\r
-<?php\r
- //ket thuc phan trinh bay chinh\r
-\r
- if (empty($noheader)) {\r
- print_footer($course);\r
- }\r
-?>\r
+<?php // $Id$
+
+ require_once("../../config.php");
+ require_once('locallib.php');
+
+ $id = optional_param('id', '', PARAM_INT); // Course Module ID, or
+ $a = optional_param('a', '', PARAM_INT); // SCORM ID
+ $b = optional_param('b', '', PARAM_INT); // SCO ID
+ $user = optional_param('user', '', PARAM_INT); // User ID
+
+ if (!empty($id)) {
+ if (! $cm = get_record("course_modules", "id", $id)) {
+ error("Course Module ID was incorrect");
+ }
+ if (! $course = get_record("course", "id", $cm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+ } else {
+ if (!empty($b)) {
+ if (! $sco = get_record("scorm_scoes", "id", $b)) {
+ error("Scorm activity is incorrect");
+ }
+ $a = $sco->scorm;
+ }
+ if (!empty($a)) {
+ if (! $scorm = get_record("scorm", "id", $a)) {
+ error("Course module is incorrect");
+ }
+ if (! $course = get_record("course", "id", $scorm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+ error("Course Module ID was incorrect");
+ }
+ }
+ }
+
+ require_login($course->id, false, $cm);
+ require_capability('mod/scorm:viewgrades', get_context_instance(COTNEXT_MODULE, $cm->id));
+
+ add_to_log($course->id, "scorm", "report", "cofficientsetting.php?id=$cm->id", "$scorm->id");
+
+/// Print the page header
+ if (empty($noheader)) {
+ if ($course->category) {
+ $navigation = "<a href=\"../../course/view.php?id=$course->id\">$course->shortname</a> ->";
+ } else {
+ $navigation = '';
+ }
+
+ $strscorms = get_string("modulenameplural", "scorm");
+ $strscorm = get_string("modulename", "scorm");
+ $strreport = get_string("report", "scorm");
+ $strname = get_string('name');
+ $strcoefficient = get_string('coefficient','scorm');
+ if (empty($b)) {
+ print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+ "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+ -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a> -> $strcoefficient",
+ "", "", true);
+ } else {
+ print_header("$course->shortname: ".format_string($scorm->name), "$course->fullname",
+ "$navigation <a href=\"index.php?id=$course->id\">$strscorms</a>
+ -> <a href=\"view.php?id=$cm->id\">".format_string($scorm->name,true)."</a>
+ -> <a href=\"report.php?id=$cm->id\">$strreport</a> -> $sco->title",
+ "", "", true);
+ }
+ print_heading(format_string($scorm->name));
+ }
+
+ $scormpixdir = $CFG->modpixpath.'/scorm/pix';
+
+ //Phan trinh bay chinh
+?>
+<script type="text/javascript">
+function validate_form()
+{
+ return true;
+}
+</script>
+<form name="form" method="post" action="coefficientconfirm.php" onsubmit="return validate_form();" >
+ <table width="50%" border="0">
+ <tr>
+ <td class="scormtableheader"><?php echo(get_string('title','scorm')); ?></td>
+ <td class="scormtableheader"><?php echo(get_string('coefficient','scorm')); ?></td>
+ </tr>
+
+ <?php
+ $examScoes = get_records_select('scorm_scoes', 'scorm ='.($scorm->id).' and minnormalizedmeasure > -1');
+ if(!empty($examScoes))
+ {
+
+ foreach ($examScoes as $examSco){
+ echo "<tr><td>";
+ echo "$examSco->identifier.</td><td><input type='text' name='$examSco->id' class='scormtextbox' value=$examSco->score_coefficient /></td></tr><br>";
+ }
+ }
+
+?>
+ </table>
+<br>
+<input type="hidden" name="id" value="<?php p($id) ?>" />
+<input type="submit" value="<?php print_string('savechanges') ?>" />
+</form>
+<?php
+ //ket thuc phan trinh bay chinh
+
+ if (empty($noheader)) {
+ print_footer($course);
+ }
+?>
-<?php\r
- require_once('../../config.php');\r
- require_once('locallib.php');\r
- \r
- $id = optional_param('id', '', PARAM_INT); // Course Module ID, or\r
- $a = optional_param('a', '', PARAM_INT); // scorm ID\r
- $scoid = required_param('scoid', PARAM_INT); // sco ID\r
-// $attempt = required_param('attempt', PARAM_INT); // attempt number\r
- $attempt = $SESSION->scorm_attempt;\r
-\r
-\r
- if (!empty($id)) {\r
- if (! $cm = get_record("course_modules", "id", $id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $cm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
- error("Course module is incorrect");\r
- }\r
- } else if (!empty($a)) {\r
- if (! $scorm = get_record("scorm", "id", $a)) {\r
- error("Course module is incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $scorm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- } else {\r
- error('A required parameter is missing');\r
- }\r
-\r
- require_login($course->id, false, $cm);\r
-\r
- if (confirm_sesskey() && (!empty($scoid))) {\r
- $result = true;\r
- if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE,$cm->id))) {\r
- foreach ($_POST as $element => $value) {\r
- if (substr($element,0,3) == 'cmi') {\r
- $element = str_replace('__','.',$element);\r
- $element = preg_replace('/_(\d+)/',".\$1",$element);\r
- $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value) && $result;\r
- }\r
- }\r
- }\r
- if ($result) {\r
- echo "true\n0";\r
- } else {\r
- echo "false\n101";\r
- }\r
- }\r
-?>\r
-\r
+<?php
+ require_once('../../config.php');
+ require_once('locallib.php');
+
+ $id = optional_param('id', '', PARAM_INT); // Course Module ID, or
+ $a = optional_param('a', '', PARAM_INT); // scorm ID
+ $scoid = required_param('scoid', PARAM_INT); // sco ID
+// $attempt = required_param('attempt', PARAM_INT); // attempt number
+ $attempt = $SESSION->scorm_attempt;
+
+
+ if (!empty($id)) {
+ if (! $cm = get_record("course_modules", "id", $id)) {
+ error("Course Module ID was incorrect");
+ }
+ if (! $course = get_record("course", "id", $cm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+ } else if (!empty($a)) {
+ if (! $scorm = get_record("scorm", "id", $a)) {
+ error("Course module is incorrect");
+ }
+ if (! $course = get_record("course", "id", $scorm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+ error("Course Module ID was incorrect");
+ }
+ } else {
+ error('A required parameter is missing');
+ }
+
+ require_login($course->id, false, $cm);
+
+ if (confirm_sesskey() && (!empty($scoid))) {
+ $result = true;
+ if (has_capability('mod/scorm:savetrack', get_context_instance(CONTEXT_MODULE,$cm->id))) {
+ foreach ($_POST as $element => $value) {
+ if (substr($element,0,3) == 'cmi') {
+ $element = str_replace('__','.',$element);
+ $element = preg_replace('/_(\d+)/',".\$1",$element);
+ $result = scorm_insert_track($USER->id, $scorm->id, $scoid, $attempt, $element, $value) && $result;
+ }
+ }
+ }
+ if ($result) {
+ echo "true\n0";
+ } else {
+ echo "false\n101";
+ }
+ }
+?>
+
-<?php // $Id$\r
-\r
- require_once("../../config.php");\r
-\r
- $id = required_param('id', PARAM_INT); // course id\r
-\r
- if (!empty($id)) {\r
- if (! $course = get_record("course", "id", $id)) {\r
- error("Course ID is incorrect");\r
- }\r
- } else {\r
- error('A required parameter is missing');\r
- }\r
-\r
- require_course_login($course);\r
-\r
- add_to_log($course->id, "scorm", "view all", "index.php?id=$course->id", "");\r
-\r
- $strscorm = get_string("modulename", "scorm");\r
- $strscorms = get_string("modulenameplural", "scorm");\r
- $strweek = get_string("week");\r
- $strtopic = get_string("topic");\r
- $strname = get_string("name");\r
- $strsummary = get_string("summary");\r
- $strreport = get_string("report",'scorm');\r
- $strlastmodified = get_string("lastmodified");\r
-\r
- print_header_simple("$strscorms", "", "$strscorms",\r
- "", "", true, "", navmenu($course));\r
-\r
- if ($course->format == "weeks" or $course->format == "topics") {\r
- $sortorder = "cw.section ASC";\r
- } else {\r
- $sortorder = "m.timemodified DESC";\r
- }\r
-\r
- if (! $scorms = get_all_instances_in_course("scorm", $course)) {\r
- notice("There are no scorms", "../../course/view.php?id=$course->id");\r
- exit;\r
- }\r
-\r
- if ($course->format == "weeks") {\r
- $table->head = array ($strweek, $strname, $strsummary, $strreport);\r
- $table->align = array ("center", "left", "left", "left");\r
- } else if ($course->format == "topics") {\r
- $table->head = array ($strtopic, $strname, $strsummary, $strreport);\r
- $table->align = array ("center", "left", "left", "left");\r
- } else {\r
- $table->head = array ($strlastmodified, $strname, $strsummary, $strreport);\r
- $table->align = array ("left", "left", "left", "left");\r
- }\r
-\r
- foreach ($scorms as $scorm) {\r
-\r
- $context = get_context_instance(CONTEXT_MODULE,$scorm->coursemodule);\r
- $tt = "";\r
- if ($course->format == "weeks" or $course->format == "topics") {\r
- if ($scorm->section) {\r
- $tt = "$scorm->section";\r
- }\r
- } else {\r
- $tt = userdate($scorm->timemodified);\r
- }\r
- $report = ' ';\r
- if (has_capability('mod/scorm:viewreport', $context)) {\r
- $trackedusers = get_record('scorm_scoes_track', 'scormid', $scorm->id, '', '', '', '', 'count(distinct(userid)) as c');\r
- if ($trackedusers->c > 0) {\r
- $reportshow = '<a href="report.php?a='.$scorm->id.'">'.get_string('viewallreports','scorm',$trackedusers->c).'</a></div>';\r
- } else {\r
- $reportshow = get_string('noreports','scorm');\r
- }\r
- } else if (has_capability('mod/scorm:viewscores', $context)) {\r
- require_once('locallib.php');\r
- $report = scorm_grade_user(get_records('scorm_scoes','scorm',$scorm->id), $USER->id, $scorm->grademethod);\r
- $reportshow = get_string('score','scorm').": ".$report; \r
- }\r
- if (!$scorm->visible) {\r
- //Show dimmed if the mod is hidden\r
- $table->data[] = array ($tt, "<a class=\"dimmed\" href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",\r
- format_text($scorm->summary),$reportshow);\r
- } else {\r
- //Show normal if the mod is visible\r
- $table->data[] = array ($tt, "<a href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",\r
- format_text($scorm->summary), $reportshow);\r
- }\r
- }\r
-\r
- echo "<br />";\r
-\r
- print_table($table);\r
-\r
- print_footer($course);\r
-\r
-?>\r
-\r
+<?php // $Id$
+
+ require_once("../../config.php");
+
+ $id = required_param('id', PARAM_INT); // course id
+
+ if (!empty($id)) {
+ if (! $course = get_record("course", "id", $id)) {
+ error("Course ID is incorrect");
+ }
+ } else {
+ error('A required parameter is missing');
+ }
+
+ require_course_login($course);
+
+ add_to_log($course->id, "scorm", "view all", "index.php?id=$course->id", "");
+
+ $strscorm = get_string("modulename", "scorm");
+ $strscorms = get_string("modulenameplural", "scorm");
+ $strweek = get_string("week");
+ $strtopic = get_string("topic");
+ $strname = get_string("name");
+ $strsummary = get_string("summary");
+ $strreport = get_string("report",'scorm');
+ $strlastmodified = get_string("lastmodified");
+
+ print_header_simple("$strscorms", "", "$strscorms",
+ "", "", true, "", navmenu($course));
+
+ if ($course->format == "weeks" or $course->format == "topics") {
+ $sortorder = "cw.section ASC";
+ } else {
+ $sortorder = "m.timemodified DESC";
+ }
+
+ if (! $scorms = get_all_instances_in_course("scorm", $course)) {
+ notice("There are no scorms", "../../course/view.php?id=$course->id");
+ exit;
+ }
+
+ if ($course->format == "weeks") {
+ $table->head = array ($strweek, $strname, $strsummary, $strreport);
+ $table->align = array ("center", "left", "left", "left");
+ } else if ($course->format == "topics") {
+ $table->head = array ($strtopic, $strname, $strsummary, $strreport);
+ $table->align = array ("center", "left", "left", "left");
+ } else {
+ $table->head = array ($strlastmodified, $strname, $strsummary, $strreport);
+ $table->align = array ("left", "left", "left", "left");
+ }
+
+ foreach ($scorms as $scorm) {
+
+ $context = get_context_instance(CONTEXT_MODULE,$scorm->coursemodule);
+ $tt = "";
+ if ($course->format == "weeks" or $course->format == "topics") {
+ if ($scorm->section) {
+ $tt = "$scorm->section";
+ }
+ } else {
+ $tt = userdate($scorm->timemodified);
+ }
+ $report = ' ';
+ if (has_capability('mod/scorm:viewreport', $context)) {
+ $trackedusers = get_record('scorm_scoes_track', 'scormid', $scorm->id, '', '', '', '', 'count(distinct(userid)) as c');
+ if ($trackedusers->c > 0) {
+ $reportshow = '<a href="report.php?a='.$scorm->id.'">'.get_string('viewallreports','scorm',$trackedusers->c).'</a></div>';
+ } else {
+ $reportshow = get_string('noreports','scorm');
+ }
+ } else if (has_capability('mod/scorm:viewscores', $context)) {
+ require_once('locallib.php');
+ $report = scorm_grade_user(get_records('scorm_scoes','scorm',$scorm->id), $USER->id, $scorm->grademethod);
+ $reportshow = get_string('score','scorm').": ".$report;
+ }
+ if (!$scorm->visible) {
+ //Show dimmed if the mod is hidden
+ $table->data[] = array ($tt, "<a class=\"dimmed\" href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",
+ format_text($scorm->summary),$reportshow);
+ } else {
+ //Show normal if the mod is visible
+ $table->data[] = array ($tt, "<a href=\"view.php?id=$scorm->coursemodule\">".format_string($scorm->name,true)."</a>",
+ format_text($scorm->summary), $reportshow);
+ }
+ }
+
+ echo "<br />";
+
+ print_table($table);
+
+ print_footer($course);
+
+?>
+
-<?php\r
- require_once("../../config.php");\r
- require_once('locallib.php');\r
-\r
- $id = optional_param('id', '', PARAM_INT); // Course Module ID, or\r
- $a = optional_param('a', '', PARAM_INT); // scorm ID\r
- $scoid = required_param('scoid', PARAM_INT); // sco ID\r
-\r
- if (!empty($id)) {\r
- if (! $cm = get_coursemodule_from_id('scorm', $id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $cm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $scorm = get_record("scorm", "id", $cm->instance)) {\r
- error("Course module is incorrect");\r
- }\r
- } else if (!empty($a)) {\r
- if (! $scorm = get_record("scorm", "id", $a)) {\r
- error("Course module is incorrect");\r
- }\r
- if (! $course = get_record("course", "id", $scorm->course)) {\r
- error("Course is misconfigured");\r
- }\r
- if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {\r
- error("Course Module ID was incorrect");\r
- }\r
- } else {\r
- error('A required parameter is missing');\r
- }\r
-\r
- require_login($course->id, false, $cm);\r
- if (!empty($scoid)) {\r
- //\r
- // Direct SCO request\r
- //\r
- if ($sco = get_record("scorm_scoes","id",$scoid)) {\r
- if ($sco->launch == '') {\r
- // Search for the next launchable sco\r
- if ($scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>'' AND id>".$sco->id,"id ASC")) {\r
- $sco = current($scoes);\r
- }\r
- }\r
- }\r
- }\r
- //\r
- // If no sco was found get the first of SCORM package\r
- //\r
- if (!isset($sco)) {\r
- $scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>''","id ASC");\r
- $sco = current($scoes);\r
- }\r
-\r
- //\r
- // Forge SCO URL\r
- //\r
- $connector = '';\r
- $version = substr($scorm->version,0,4);\r
- if (!empty($sco->parameters) || ($version == 'AICC')) {\r
- if (stripos($sco->launch,'?') !== false) {\r
- $connector = '&';\r
- } else {\r
- $connector = '?';\r
- }\r
- if (!empty($sco->parameters) && ($sco->parameters[0] == '?')) {\r
- $sco->parameters = substr($sco->parameters,1);\r
- }\r
- }\r
- \r
- if ($version == 'AICC') {\r
- if (!empty($sco->parameters)) {\r
- $sco->parameters = '&'. $sco->parameters;\r
- }\r
- $launcher = $sco->launch.$connector.'aicc_sid='.sesskey().'&aicc_url='.$CFG->wwwroot.'/mod/scorm/type/aicc/aicc.php'.$sco->parameters;\r
- } else {\r
- $launcher = $sco->launch.$connector.$sco->parameters;\r
- }\r
- \r
- if (scorm_external_link($sco->launch)) {\r
- $result = $launcher;\r
- } else if ($scorm->reference[0] == '#') {\r
- require_once($repositoryconfigfile);\r
- $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch;\r
- } else {\r
- if (basename($scorm->reference) == 'imsmanifest.xml') {\r
- $basedir = dirname($scorm->reference);\r
- } else {\r
- $basedir = 'moddata/scorm/'.$scorm->id;\r
- }\r
- if ($CFG->slasharguments) {\r
- $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher;\r
- } else {\r
- $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher;\r
- }\r
- }\r
-?>\r
-<html>\r
- <head>\r
- <title>LoadSCO</title>\r
- <script language="javascript" type="text/javascript">\r
- <!--\r
- setTimeout('document.location = "<?php echo $result ?>";',2000);\r
- -->\r
- </script>\r
- <noscript>\r
- <meta http-equiv="refresh" content="2;url=<?php echo $result ?>" />\r
- </noscript> \r
- </head>\r
- <body>\r
- \r
- </body>\r
-</html>\r
+<?php
+ require_once("../../config.php");
+ require_once('locallib.php');
+
+ $id = optional_param('id', '', PARAM_INT); // Course Module ID, or
+ $a = optional_param('a', '', PARAM_INT); // scorm ID
+ $scoid = required_param('scoid', PARAM_INT); // sco ID
+
+ if (!empty($id)) {
+ if (! $cm = get_coursemodule_from_id('scorm', $id)) {
+ error("Course Module ID was incorrect");
+ }
+ if (! $course = get_record("course", "id", $cm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $scorm = get_record("scorm", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+ } else if (!empty($a)) {
+ if (! $scorm = get_record("scorm", "id", $a)) {
+ error("Course module is incorrect");
+ }
+ if (! $course = get_record("course", "id", $scorm->course)) {
+ error("Course is misconfigured");
+ }
+ if (! $cm = get_coursemodule_from_instance("scorm", $scorm->id, $course->id)) {
+ error("Course Module ID was incorrect");
+ }
+ } else {
+ error('A required parameter is missing');
+ }
+
+ require_login($course->id, false, $cm);
+ if (!empty($scoid)) {
+ //
+ // Direct SCO request
+ //
+ if ($sco = get_record("scorm_scoes","id",$scoid)) {
+ if ($sco->launch == '') {
+ // Search for the next launchable sco
+ if ($scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>'' AND id>".$sco->id,"id ASC")) {
+ $sco = current($scoes);
+ }
+ }
+ }
+ }
+ //
+ // If no sco was found get the first of SCORM package
+ //
+ if (!isset($sco)) {
+ $scoes = get_records_select("scorm_scoes","scorm=".$scorm->id." AND launch<>''","id ASC");
+ $sco = current($scoes);
+ }
+
+ //
+ // Forge SCO URL
+ //
+ $connector = '';
+ $version = substr($scorm->version,0,4);
+ if (!empty($sco->parameters) || ($version == 'AICC')) {
+ if (stripos($sco->launch,'?') !== false) {
+ $connector = '&';
+ } else {
+ $connector = '?';
+ }
+ if (!empty($sco->parameters) && ($sco->parameters[0] == '?')) {
+ $sco->parameters = substr($sco->parameters,1);
+ }
+ }
+
+ if ($version == 'AICC') {
+ if (!empty($sco->parameters)) {
+ $sco->parameters = '&'. $sco->parameters;
+ }
+ $launcher = $sco->launch.$connector.'aicc_sid='.sesskey().'&aicc_url='.$CFG->wwwroot.'/mod/scorm/type/aicc/aicc.php'.$sco->parameters;
+ } else {
+ $launcher = $sco->launch.$connector.$sco->parameters;
+ }
+
+ if (scorm_external_link($sco->launch)) {
+ $result = $launcher;
+ } else if ($scorm->reference[0] == '#') {
+ require_once($repositoryconfigfile);
+ $result = $CFG->repositorywebroot.substr($scorm->reference,1).'/'.$sco->launch;
+ } else {
+ if (basename($scorm->reference) == 'imsmanifest.xml') {
+ $basedir = dirname($scorm->reference);
+ } else {
+ $basedir = 'moddata/scorm/'.$scorm->id;
+ }
+ if ($CFG->slasharguments) {
+ $result = $CFG->wwwroot.'/file.php/'.$scorm->course.'/'.$basedir.'/'.$launcher;
+ } else {
+ $result = $CFG->wwwroot.'/file.php?file=/'.$scorm->course.'/'.$basedir.'/'.$launcher;
+ }
+ }
+?>
+<html>
+ <head>
+ <title>LoadSCO</title>
+ <script language="javascript" type="text/javascript">
+ <!--
+ setTimeout('document.location = "<?php echo $result ?>";',2000);
+ -->
+ </script>
+ <noscript>
+ <meta http-equiv="refresh" content="2;url=<?php echo $result ?>" />
+ </noscript>
+ </head>
+ <body>
+
+ </body>
+</html>
-<?php\r
- require_once($CFG->dirroot.'/mod/scorm/configurations.php');\r
- if (!isset($form->name)) {\r
- $form->name = '';\r
- }\r
- if (!isset($form->reference)) {\r
- $form->reference = '';\r
- }\r
- if (!isset($form->summary)) {\r
- $form->summary = '';\r
- }\r
- if (!isset($form->launch)) {\r
- $form->launch = '';\r
- }\r
- if (!isset($form->auto)) {\r
- $form->auto = '';\r
- }\r
- if (!isset($form->popup)) {\r
- $form->popup = 0;\r
- }\r
- if (!isset($form->datadir)) {\r
- $form->datadir = '';\r
- }\r
- if (!isset($form->maxgrade)) {\r
- $form->maxgrade = '';\r
- }\r
- if (!isset($form->grademethod)) {\r
- $form->grademethod = 0;\r
- }\r
- if (!isset($form->maxattempt)) {\r
- $form->maxattempt = 1;\r
- }\r
- if (!isset($form->whatgrade)) {\r
- $form->whatgrade = 0;\r
- }\r
- if (!isset($form->hidebrowse)) {\r
- $form->hidebrowse = 0;\r
- }\r
- if (!isset($form->hidetoc)) {\r
- $form->hidetoc = 0;\r
- }\r
- if (!isset($form->hidenav)) {\r
- $form->hidenav = 0;\r
- }\r
- if (!isset($form->width)) {\r
- $form->width = $CFG->scorm_framewidth;\r
- }\r
- if ((strpos($form->width,'%') === false) && ($form->width <= 100)) {\r
- $form->width .= '%';\r
- }\r
- if (!isset($form->height)) {\r
- $form->height = $CFG->scorm_frameheight;\r
- }\r
- if ((strpos($form->height,'%') === false) && ($form->height <= 100)) {\r
- $form->height .= '%';\r
- }\r
- if (!isset($form->options) || empty($form->options)) {\r
- $form->options = $stdoptions;\r
- }\r
- $options = explode(',',$form->options);\r
- $window = new stdClass();\r
- foreach ($options as $option) {\r
- list($element,$value) = explode('=',$option);\r
- $element = trim($element);\r
- $window->$element = trim($value)==1?'checked':''; \r
- }\r
- if (!isset($form->pkgtype)) {\r
- $form->pkgtype = '';\r
- }\r
- $scormid = '';\r
- if (!empty($form->instance)) {\r
- $scormid = '&instance='.$form->instance;\r
- }\r
- $datadir = '';\r
- if (!empty($form->datadir)) {\r
- $datadir = '&datadir='.$form->datadir;\r
- }\r
- $sessionkey = '';\r
- if (!empty($form->sesskey)) {\r
- $sessionkey = '&sesskey='.$form->sesskey;\r
- }\r
-\r
- $strfilename = get_string('coursepacket', 'scorm');\r
- $strchooseafile = get_string('chooseapacket', 'scorm');\r
- $strbrowserepository = get_string('browserepository', 'scorm');\r
- $striframe = get_string('iframe', 'scorm');\r
- $striframedisplay = get_string('iframedisplay', 'scorm');\r
- $strnewwindow = get_string('popup', 'scorm');\r
- $strnewwindowopen = get_string('popupopen', 'scorm');\r
- $strheight = get_string('height', 'scorm');\r
- $strwidth = get_string('width', 'scorm');\r
- $strresizable = get_string('resizable', 'scorm');\r
- $strscrollbars = get_string('scrollbars', 'scorm');\r
- $strdirectories = get_string('directories', 'scorm');\r
- $strlocation = get_string('location', 'scorm');\r
- $strmenubar = get_string('menubar', 'scorm');\r
- $strtoolbar = get_string('toolbar', 'scorm');\r
- $strstatus = get_string('statusbar', 'scorm');\r
-?>\r
-\r
-<script type="text/javascript" src="<?php p($CFG->wwwroot) ?>/mod/scorm/request.js" ></script>\r
-<script type="text/javascript">\r
- function validate_scorm(theform,filename,confirmed) {\r
- var confirmedstr = '';\r
- if (confirmed == true) {\r
- confirmedstr = '&confirmed=true';\r
- }\r
-\r
- var myRequest = NewHttpReq();\r
- result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/validate.php","id=<?php p($form->course) ?>&reference="+filename+"<?php echo $sessionkey.$scormid.$datadir ?>");\r
- //alert(result);\r
- results = result.split('\n');\r
- result = '';\r
- errorlogs = '';\r
- datadir = '';\r
- for (i=0;i<results.length;i++) {\r
- element = results[i].split('=');\r
- switch(element[0]) {\r
- case 'result':\r
- result = element[1];\r
- break;\r
- case 'launch':\r
- launch = element[1];\r
- break;\r
- case 'datadir':\r
- datadir = element[1];\r
- break;\r
- case 'pkgtype':\r
- pkgtype = element[1];\r
- break;\r
- case 'errorlogs':\r
- i++;\r
- do {\r
- errorlogs.concat(results[i]+'\n');\r
- i++;\r
- } while (i<results.lenght());\r
-\r
- break;\r
- }\r
- }\r
- if ((result == "found") || (result == "regular")) {\r
- theform.datadir.value = datadir;\r
- theform.pkgtype.value = pkgtype;\r
- theform.launch.value = launch;\r
- if (theform.mode.value == 'add') {\r
- theform.parse.value = 1;\r
- } else if (launch == 0) {\r
- theform.parse.value = 1;\r
- }\r
- return true;\r
- } else {\r
- if (result == "confirm") {\r
- response = confirm("<?php print_string('confirmloosetracks','scorm') ?>");\r
- if (response == true) {\r
- return validate_scorm(theform,filename,true);\r
- } else {\r
- return false;\r
- }\r
- } else {\r
- result = '<?php print_string('validation','scorm') ?>: '+ result + '\n';\r
- if (errorlogs != '') {\r
- result.concat('<?php print_string('errorlogs','scorm') ?>:\n'+errorlogs);\r
- }\r
- alert(result);\r
- return false;\r
- }\r
- }\r
- }\r
-\r
- function checkscormform (whatcheck,checkvalue,whatset) {\r
- if (whatcheck.options[whatcheck.selectedIndex].value == checkvalue) {\r
- whatset.disabled = true;\r
- } else {\r
- whatset.disabled = false;\r
- }\r
- }\r
- \r
- function showhide (id, set) {\r
- divobj = document.getElementById(id);\r
- butobj = document.getElementById(id+'button');\r
- prefobj = document.getElementById(id+'pref');\r
- if (set == true) {\r
- if (prefobj.value == '1') {\r
- divobj.style.display = 'block';\r
- butobj.value = '<?php print_string('hidesettings') ?>';\r
- } else {\r
- divobj.style.display = 'none';\r
- butobj.value = '<?php print_string('showsettings') ?>...';\r
- }\r
- } else {\r
- if (prefobj.value == '1') {\r
- divobj.style.display = 'none';\r
- butobj.value = '<?php print_string('showsettings') ?>...';\r
- prefobj.value = '0';\r
- } else {\r
- divobj.style.display = 'block';\r
- butobj.value = '<?php print_string('hidesettings') ?>';\r
- prefobj.value = '1';\r
- }\r
- }\r
- }\r
-</script>\r
-\r
-<form name="form" method="post" action="mod.php?goto=" onsubmit="return validate_scorm(document.form,document.form.reference.value,false,false);">\r
- <table cellpadding="5">\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('name') ?>:</b></td>\r
- <td>\r
- <input type="text" name="name" size="50" value="<?php p($form->name) ?>" alt="<?php print_string('name') ?>" />\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('summary') ?>:</b><br />\r
- <?php helpbutton('summary', get_string('summary'), 'scorm', true, true) ?>\r
- </td>\r
- <td>\r
- <?php print_textarea($usehtmleditor, 10, 50, 680, 400, 'summary', $form->summary); ?>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right" nowrap="nowrap">\r
- <b><?php echo $strfilename?>:</b>\r
- </td>\r
- <td>\r
- <input name="reference" size="50" value="<?php echo $form->reference ?>" alt="<?php echo $strfilename ?>" /> \r
- <?php\r
- button_to_popup_window ('/files/index.php?id='.$course->id.'&choose=form.reference',\r
- 'coursefiles', $strchooseafile, 500, 750, $strchooseafile);\r
- require_once($repositoryconfigfile);\r
- if ($CFG->repositoryactivate) {\r
- button_to_popup_window ($repositorybrowser.'?choose=form.reference',\r
- 'browserepository', $strbrowserepository, 500, 750, $strbrowserepository);\r
- }\r
- helpbutton('package', get_string('coursepacket', 'scorm'), 'scorm', true);\r
- ?>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('grademethod', 'scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- choose_from_menu($SCORM_GRADE_METHOD, 'grademethod', (int) $form->grademethod, '','checkscormform(this,0,document.form.maxgrade);');\r
- helpbutton('grademethod', get_string('grademethod','scorm'), 'scorm');\r
- ?>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('maximumgrade') ?>:</b></td>\r
- <td>\r
- <?php\r
- for ($i=100; $i>=1; $i--) {\r
- $grades[$i] = $i;\r
- }\r
- $disabled = $form->grademethod=='0';\r
- choose_from_menu($grades, 'maxgrade', (int) $form->maxgrade, '','','0',false,$disabled);\r
- helpbutton('maxgrade', get_string('maximumgrade'), 'scorm');\r
- ?>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('maximumattempts','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- for ($i=1; $i<=$CFG->scorm_maxattempts; $i++) {\r
- if ($i == 1) {\r
- $attempts[$i] = $i . ' ' . get_string('attempt','scorm');\r
- } else {\r
- $attempts[$i] = $i . ' ' . get_string('attempts','scorm');\r
- }\r
- }\r
- choose_from_menu($attempts, 'maxattempt', (int) $form->maxattempt, get_string('nolimit','scorm'),'checkscormform(this,1,document.form.whatgrade);');\r
- helpbutton('maxattempt', get_string('maximumattempts','scorm'), 'scorm');\r
- ?>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td align="right"><b><?php print_string('whatgrade','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- $disabled = (int) $form->maxattempt === 1;\r
- choose_from_menu($SCORM_WHAT_GRADE, 'whatgrade', (int) $form->whatgrade, '','','0',false,$disabled);\r
- helpbutton('whatgrade', get_string('whatgrade','scorm'), 'scorm');\r
- ?>\r
- </td>\r
- </tr>\r
- <tr><td colspan="2"><hr /></td></tr>\r
-\r
- <tr>\r
- <td align="right"><b><?php print_string('advanced', 'scorm') ?>:</b></td>\r
- <td>\r
- <input type="button" value="<?php print_string('hidesettings') ?>" id="advancedsettingsbutton" onclick="javascript: return showhide('advancedsettings');" />\r
- <input type="hidden" name="advancedsettingspref" id="advancedsettingspref" \r
- value="<?php echo get_user_preferences('scorm_advancedsettingspref', $CFG->scorm_advancedsettings); ?>" />\r
- <?php helpbutton('advanced', get_string('advanced', 'scorm'), 'scorm', true) ?>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td colspan="2">\r
- <div id="advancedsettings">\r
- <table align="center">\r
- <tr>\r
- <td align="right"><b><?php print_string('autocontinue','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- $options = array();\r
- $options[0]=get_string('no');\r
- $options[1]=get_string('yes');\r
- choose_from_menu ($options, 'auto', (int) $form->auto,'');\r
- helpbutton('autocontinue', get_string('autocontinue','scorm'), 'scorm', true);\r
- ?>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td align="right"><b><?php print_string('hidebrowse','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- $options = array();\r
- $options[0]=get_string('no');\r
- $options[1]=get_string('yes');\r
- choose_from_menu ($options, 'hidebrowse', (int) $form->hidebrowse, '');\r
- helpbutton('browsemode', get_string('hidebrowse','scorm'), 'scorm', true);\r
- ?>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td align="right"><b><?php print_string('hidetoc','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- $options = array();\r
- $options[1]=get_string('hidden','scorm');\r
- $options[0]=get_string('sided','scorm');\r
- $options[2]=get_string('popupmenu','scorm');\r
- choose_from_menu ($options, 'hidetoc', (int) $form->hidetoc, '');\r
- ?>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td align="right"><b><?php print_string('hidenav','scorm') ?>:</b></td>\r
- <td>\r
- <?php\r
- $options = array();\r
- $options[0]=get_string('no');\r
- $options[1]=get_string('yes');\r
- choose_from_menu ($options, 'hidenav', (int) $form->hidenav, '');\r
- ?>\r
- </td>\r
- </tr>\r
- </table>\r
- </div>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td align="right"><b><?php print_string('window', 'scorm') ?>:</b></td>\r
- <td>\r
- <input type="button" value="<?php print_string('hidesettings') ?>" id="windowsettingsbutton" onclick="javascript: return showhide('windowsettings');" />\r
- <input type="hidden" name="windowsettingspref" id="windowsettingspref" \r
- value="<?php echo get_user_preferences('scorm_windowsettingspref', $CFG->scorm_windowsettings); ?>" />\r
- <?php helpbutton('window', get_string('window', 'scorm'), 'scorm', true) ?>\r
- </td>\r
- </tr>\r
- <tr>\r
- <td colspan="2">\r
- <div id="windowsettings">\r
- <table align="center">\r
- <tr valign="top">\r
- <td>\r
- <b><?php print_string('stagesize','scorm'); ?></b>\r
- <?php helpbutton('size', get_string('stagesize', 'scorm'), 'scorm', true) ?><br />\r
- <input name="width" type="text" size="4" value="<?php p($form->width) ?>" alt="<?php p($strwidth) ?>" />\r
- <label for="width"><?php p($strwidth) ?></label><br />\r
- <input name="height" type="text" size="4" value="<?php p($form->height) ?>" alt="<?php p($strheight) ?>" />\r
- <label for="height"><?php p($strheight) ?></label>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td>\r
- <script type="text/javascript">\r
- var popupitems = ["<?php echo implode('","',array_keys($SCORM_POPUP_OPTIONS)); ?>"];\r
- </script>\r
- <br /><b><?php print_string('display','scorm'); ?>:</b><br />\r
- <input type="radio" \r
- name="popup"\r
- value="0" alt="<?php p($striframe) ?>" \r
- <?php echo ($form->popup == 0) ? "checked=\"checked\"" : "" ?> \r
- onclick="return lockoptions('form', 'popup[1]', popupitems);"\r
- />\r
- <b title="<?php p($striframedisplay) ?>"><?php p($striframe) ?></b>\r
- </td>\r
- </tr>\r
- <tr valign="top">\r
- <td>\r
- <input name="popup" \r
- type="radio" \r
- value="1" \r
- alt="<?php p($strnewwindow)?>" \r
- <?php echo ($form->popup == 1) ? 'checked="checked"' : '' ?>\r
- onclick="return lockoptions('form', 'popup[1]', popupitems);"\r
- />\r
- <b title="<?php p($strnewwindowopen) ?>"><?php p($strnewwindow) ?></b>\r
- <blockquote>\r
- <?php\r
- foreach ($window as $name => $value) {\r
- echo "<input name=\"h$name\" type=\"hidden\" value=\"0\"/>\n";\r
- echo "<input name=\"$name\" type=\"checkbox\" value=\"1\" ".$window->$name." alt=\"$name\" />\n";\r
- $stringname = "str$name";\r
- echo $$stringname."<br />\n";\r
- }\r
- ?>\r
- <script type="text/javascript">\r
- lockoptions('form','popup[1]', popupitems);\r
- </script>\r
- </blockquote>\r
- </td>\r
- </tr>\r
- </table>\r
- </div>\r
- <script language="javascript" type="text/javascript">\r
- showhide('advancedsettings', true);\r
- showhide('windowsettings', true);\r
- </script>\r
- </td>\r
- </tr>\r
- </table>\r
- <input type="hidden" name="datadir" value="<?php p($form->datadir) ?>" />\r
- <input type="hidden" name="pkgtype" value="<?php p($form->pkgtype) ?>" />\r
- <input type="hidden" name="launch" value="<?php p($form->launch) ?>" />\r
- <input type="hidden" name="parse" value="0" />\r
- <?php\r
- $scorms = get_all_instances_in_course('scorm', $course);\r
- $coursescorm = current($scorms);\r
- if (($course->format == 'scorm') && ((count($scorms) == 0) || ($form->instance == $coursescorm->id))) {\r
- ?>\r
- <input type="hidden" name="redirect" value="yes" />\r
- <input type="hidden" name="redirecturl" value="../course/view.php?id=<?php p($form->course) ?>" /> \r
- <?php\r
- } \r
- ?>\r
- <input type="hidden" name="course" value="<?php p($form->course) ?>" />\r
- <input type="hidden" name="sesskey" value="<?php p($form->sesskey) ?>" />\r
- <input type="hidden" name="section" value="<?php p($form->section) ?>" />\r
- <input type="hidden" name="module" value="<?php p($form->module) ?>" />\r
- <input type="hidden" name="mode" value="<?php p($form->mode) ?>" />\r
- <input type="hidden" name="coursemodule" value="<?php p($form->coursemodule) ?>" />\r
- <input type="hidden" name="modulename" value="<?php p($form->modulename) ?>" />\r
- <input type="hidden" name="instance" value="<?php p($form->instance) ?>" />\r
- <center>\r
- <input type="submit" value="<?php print_string('savechanges') ?>"/>\r
- <input type="button" name="cancel" value="<?php print_string('cancel') ?>" onclick="document.location='view.php?id=<?php echo $form->course ?>'" />\r
- </center>\r
-</form>\r
+<?php
+ require_once($CFG->dirroot.'/mod/scorm/configurations.php');
+ if (!isset($form->name)) {
+ $form->name = '';
+ }
+ if (!isset($form->reference)) {
+ $form->reference = '';
+ }
+ if (!isset($form->summary)) {
+ $form->summary = '';
+ }
+ if (!isset($form->launch)) {
+ $form->launch = '';
+ }
+ if (!isset($form->auto)) {
+ $form->auto = '';
+ }
+ if (!isset($form->popup)) {
+ $form->popup = 0;
+ }
+ if (!isset($form->datadir)) {
+ $form->datadir = '';
+ }
+ if (!isset($form->maxgrade)) {
+ $form->maxgrade = '';
+ }
+ if (!isset($form->grademethod)) {
+ $form->grademethod = 0;
+ }
+ if (!isset($form->maxattempt)) {
+ $form->maxattempt = 1;
+ }
+ if (!isset($form->whatgrade)) {
+ $form->whatgrade = 0;
+ }
+ if (!isset($form->hidebrowse)) {
+ $form->hidebrowse = 0;
+ }
+ if (!isset($form->hidetoc)) {
+ $form->hidetoc = 0;
+ }
+ if (!isset($form->hidenav)) {
+ $form->hidenav = 0;
+ }
+ if (!isset($form->width)) {
+ $form->width = $CFG->scorm_framewidth;
+ }
+ if ((strpos($form->width,'%') === false) && ($form->width <= 100)) {
+ $form->width .= '%';
+ }
+ if (!isset($form->height)) {
+ $form->height = $CFG->scorm_frameheight;
+ }
+ if ((strpos($form->height,'%') === false) && ($form->height <= 100)) {
+ $form->height .= '%';
+ }
+ if (!isset($form->options) || empty($form->options)) {
+ $form->options = $stdoptions;
+ }
+ $options = explode(',',$form->options);
+ $window = new stdClass();
+ foreach ($options as $option) {
+ list($element,$value) = explode('=',$option);
+ $element = trim($element);
+ $window->$element = trim($value)==1?'checked':'';
+ }
+ if (!isset($form->pkgtype)) {
+ $form->pkgtype = '';
+ }
+ $scormid = '';
+ if (!empty($form->instance)) {
+ $scormid = '&instance='.$form->instance;
+ }
+ $datadir = '';
+ if (!empty($form->datadir)) {
+ $datadir = '&datadir='.$form->datadir;
+ }
+ $sessionkey = '';
+ if (!empty($form->sesskey)) {
+ $sessionkey = '&sesskey='.$form->sesskey;
+ }
+
+ $strfilename = get_string('coursepacket', 'scorm');
+ $strchooseafile = get_string('chooseapacket', 'scorm');
+ $strbrowserepository = get_string('browserepository', 'scorm');
+ $striframe = get_string('iframe', 'scorm');
+ $striframedisplay = get_string('iframedisplay', 'scorm');
+ $strnewwindow = get_string('popup', 'scorm');
+ $strnewwindowopen = get_string('popupopen', 'scorm');
+ $strheight = get_string('height', 'scorm');
+ $strwidth = get_string('width', 'scorm');
+ $strresizable = get_string('resizable', 'scorm');
+ $strscrollbars = get_string('scrollbars', 'scorm');
+ $strdirectories = get_string('directories', 'scorm');
+ $strlocation = get_string('location', 'scorm');
+ $strmenubar = get_string('menubar', 'scorm');
+ $strtoolbar = get_string('toolbar', 'scorm');
+ $strstatus = get_string('statusbar', 'scorm');
+?>
+
+<script type="text/javascript" src="<?php p($CFG->wwwroot) ?>/mod/scorm/request.js" ></script>
+<script type="text/javascript">
+ function validate_scorm(theform,filename,confirmed) {
+ var confirmedstr = '';
+ if (confirmed == true) {
+ confirmedstr = '&confirmed=true';
+ }
+
+ var myRequest = NewHttpReq();
+ result = DoRequest(myRequest,"<?php p($CFG->wwwroot) ?>/mod/scorm/validate.php","id=<?php p($form->course) ?>&reference="+filename+"<?php echo $sessionkey.$scormid.$datadir ?>");
+ //alert(result);
+ results = result.split('\n');
+ result = '';
+ errorlogs = '';
+ datadir = '';
+ for (i=0;i<results.length;i++) {
+ element = results[i].split('=');
+ switch(element[0]) {
+ case 'result':
+ result = element[1];
+ break;
+ case 'launch':
+ launch = element[1];
+ break;
+ case 'datadir':
+ datadir = element[1];
+ break;
+ case 'pkgtype':
+ pkgtype = element[1];
+ break;
+ case 'errorlogs':
+ i++;
+ do {
+ errorlogs.concat(results[i]+'\n');
+ i++;
+ } while (i<results.lenght());
+
+ break;
+ }
+ }
+ if ((result == "found") || (result == "regular")) {
+ theform.datadir.value = datadir;
+ theform.pkgtype.value = pkgtype;
+ theform.launch.value = launch;
+ if (theform.mode.value == 'add') {
+ theform.parse.value = 1;
+ } else if (launch == 0) {
+ theform.parse.value = 1;
+ }
+ return true;
+ } else {
+ if (result == "confirm") {
+ response = confirm("<?php print_string('confirmloosetracks','scorm') ?>");
+ if (response == true) {
+ return validate_scorm(theform,filename,true);
+ } else {
+ return false;
+ }
+ } else {
+ result = '<?php print_string('validation','scorm') ?>: '+ result + '\n';
+ if (errorlogs != '') {
+ result.concat('<?php print_string('errorlogs','scorm') ?>:\n'+errorlogs);
+ }
+ alert(result);
+ return false;
+ }
+ }
+ }
+
+ function checkscormform (whatcheck,checkvalue,whatset) {
+ if (whatcheck.options[whatcheck.selectedIndex].value == checkvalue) {
+ whatset.disabled = true;
+ } else {
+ whatset.disabled = false;
+ }
+ }
+
+ function showhide (id, set) {
+ divobj = document.getElementById(id);
+ butobj = document.getElementById(id+'button');
+ prefobj = document.getElementById(id+'pref');
+ if (set == true) {
+ if (prefobj.value == '1') {
+ divobj.style.display = 'block';
+ butobj.value = '<?php print_string('hidesettings') ?>';
+ } else {
+ divobj.style.display = 'none';
+ butobj.value = '<?php print_string('showsettings') ?>...';
+ }
+ } else {
+ if (prefobj.value == '1') {
+ divobj.style.display = 'none';
+ butobj.value = '<?php print_string('showsettings') ?>...';
+ prefobj.value = '0';
+ } else {
+ divobj.style.display = 'block';
+ butobj.value = '<?php print_string('hidesettings') ?>';
+ prefobj.value = '1';
+ }
+ }
+ }
+</script>
+
+<form name="form" method="post" action="mod.php?goto=" onsubmit="return validate_scorm(document.form,document.form.reference.value,false,false);">
+ <table cellpadding="5">
+ <tr valign="top">
+ <td align="right"><b><?php print_string('name') ?>:</b></td>
+ <td>
+ <input type="text" name="name" size="50" value="<?php p($form->name) ?>" alt="<?php print_string('name') ?>" />
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right"><b><?php print_string('summary') ?>:</b><br />
+ <?php helpbutton('summary', get_string('summary'), 'scorm', true, true) ?>
+ </td>
+ <td>
+ <?php print_textarea($usehtmleditor, 10, 50, 680, 400, 'summary', $form->summary); ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right" nowrap="nowrap">
+ <b><?php echo $strfilename?>:</b>
+ </td>
+ <td>
+ <input name="reference" size="50" value="<?php echo $form->reference ?>" alt="<?php echo $strfilename ?>" />
+ <?php
+ button_to_popup_window ('/files/index.php?id='.$course->id.'&choose=form.reference',
+ 'coursefiles', $strchooseafile, 500, 750, $strchooseafile);
+ require_once($repositoryconfigfile);
+ if ($CFG->repositoryactivate) {
+ button_to_popup_window ($repositorybrowser.'?choose=form.reference',
+ 'browserepository', $strbrowserepository, 500, 750, $strbrowserepository);
+ }
+ helpbutton('package', get_string('coursepacket', 'scorm'), 'scorm', true);
+ ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right"><b><?php print_string('grademethod', 'scorm') ?>:</b></td>
+ <td>
+ <?php
+ choose_from_menu($SCORM_GRADE_METHOD, 'grademethod', (int) $form->grademethod, '','checkscormform(this,0,document.form.maxgrade);');
+ helpbutton('grademethod', get_string('grademethod','scorm'), 'scorm');
+ ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right"><b><?php print_string('maximumgrade') ?>:</b></td>
+ <td>
+ <?php
+ for ($i=100; $i>=1; $i--) {
+ $grades[$i] = $i;
+ }
+ $disabled = $form->grademethod=='0';
+ choose_from_menu($grades, 'maxgrade', (int) $form->maxgrade, '','','0',false,$disabled);
+ helpbutton('maxgrade', get_string('maximumgrade'), 'scorm');
+ ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right"><b><?php print_string('maximumattempts','scorm') ?>:</b></td>
+ <td>
+ <?php
+ for ($i=1; $i<=$CFG->scorm_maxattempts; $i++) {
+ if ($i == 1) {
+ $attempts[$i] = $i . ' ' . get_string('attempt','scorm');
+ } else {
+ $attempts[$i] = $i . ' ' . get_string('attempts','scorm');
+ }
+ }
+ choose_from_menu($attempts, 'maxattempt', (int) $form->maxattempt, get_string('nolimit','scorm'),'checkscormform(this,1,document.form.whatgrade);');
+ helpbutton('maxattempt', get_string('maximumattempts','scorm'), 'scorm');
+ ?>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td align="right"><b><?php print_string('whatgrade','scorm') ?>:</b></td>
+ <td>
+ <?php
+ $disabled = (int) $form->maxattempt === 1;
+ choose_from_menu($SCORM_WHAT_GRADE, 'whatgrade', (int) $form->whatgrade, '','','0',false,$disabled);
+ helpbutton('whatgrade', get_string('whatgrade','scorm'), 'scorm');
+ ?>
+ </td>
+ </tr>
+ <tr><td colspan="2"><hr /></td></tr>
+
+ <tr>
+ <td align="right"><b><?php print_string('advanced', 'scorm') ?>:</b></td>
+ <td>
+ <input type="button" value="<?php print_string('hidesettings') ?>" id="advancedsettingsbutton" onclick="javascript: return showhide('advancedsettings');" />
+ <input type="hidden" name="advancedsettingspref" id="advancedsettingspref"
+ value="<?php echo get_user_preferences('scorm_advancedsettingspref', $CFG->scorm_advancedsettings); ?>" />
+ <?php helpbutton('advanced', get_string('advanced', 'scorm'), 'scorm', true) ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <div id="advancedsettings">
+ <table align="center">
+ <tr>
+ <td align="right"><b><?php print_string('autocontinue','scorm') ?>:</b></td>
+ <td>
+ <?php
+ $options = array();
+ $options[0]=get_string('no');
+ $options[1]=get_string('yes');
+ choose_from_menu ($options, 'auto', (int) $form->auto,'');
+ helpbutton('autocontinue', get_string('autocontinue','scorm'), 'scorm', true);
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><b><?php print_string('hidebrowse','scorm') ?>:</b></td>
+ <td>
+ <?php
+ $options = array();
+ $options[0]=get_string('no');
+ $options[1]=get_string('yes');
+ choose_from_menu ($options, 'hidebrowse', (int) $form->hidebrowse, '');
+ helpbutton('browsemode', get_string('hidebrowse','scorm'), 'scorm', true);
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><b><?php print_string('hidetoc','scorm') ?>:</b></td>
+ <td>
+ <?php
+ $options = array();
+ $options[1]=get_string('hidden','scorm');
+ $options[0]=get_string('sided','scorm');
+ $options[2]=get_string('popupmenu','scorm');
+ choose_from_menu ($options, 'hidetoc', (int) $form->hidetoc, '');
+ ?>
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><b><?php print_string('hidenav','scorm') ?>:</b></td>
+ <td>
+ <?php
+ $options = array();
+ $options[0]=get_string('no');
+ $options[1]=get_string('yes');
+ choose_from_menu ($options, 'hidenav', (int) $form->hidenav, '');
+ ?>
+ </td>
+ </tr>
+ </table>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td align="right"><b><?php print_string('window', 'scorm') ?>:</b></td>
+ <td>
+ <input type="button" value="<?php print_string('hidesettings') ?>" id="windowsettingsbutton" onclick="javascript: return showhide('windowsettings');" />
+ <input type="hidden" name="windowsettingspref" id="windowsettingspref"
+ value="<?php echo get_user_preferences('scorm_windowsettingspref', $CFG->scorm_windowsettings); ?>" />
+ <?php helpbutton('window', get_string('window', 'scorm'), 'scorm', true) ?>
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ <div id="windowsettings">
+ <table align="center">
+ <tr valign="top">
+ <td>
+ <b><?php print_string('stagesize','scorm'); ?></b>
+ <?php helpbutton('size', get_string('stagesize', 'scorm'), 'scorm', true) ?><br />
+ <input name="width" type="text" size="4" value="<?php p($form->width) ?>" alt="<?php p($strwidth) ?>" />
+ <label for="width"><?php p($strwidth) ?></label><br />
+ <input name="height" type="text" size="4" value="<?php p($form->height) ?>" alt="<?php p($strheight) ?>" />
+ <label for="height"><?php p($strheight) ?></label>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <script type="text/javascript">
+ var popupitems = ["<?php echo implode('","',array_keys($SCORM_POPUP_OPTIONS)); ?>"];
+ </script>
+ <br /><b><?php print_string('display','scorm'); ?>:</b><br />
+ <input type="radio"
+ name="popup"
+ value="0" alt="<?php p($striframe) ?>"
+ <?php echo ($form->popup == 0) ? "checked=\"checked\"" : "" ?>
+ onclick="return lockoptions('form', 'popup[1]', popupitems);"
+ />
+ <b title="<?php p($striframedisplay) ?>"><?php p($striframe) ?></b>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td>
+ <input name="popup"
+ type="radio"
+ value="1"
+ alt="<?php p($strnewwindow)?>"
+ <?php echo ($form->popup == 1) ? 'checked="checked"' : '' ?>
+ onclick="return lockoptions('form', 'popup[1]', popupitems);"
+ />
+ <b title="<?php p($strnewwindowopen) ?>"><?php p($strnewwindow) ?></b>
+ <blockquote>
+ <?php
+ foreach ($window as $name => $value) {
+ echo "<input name=\"h$name\" type=\"hidden\" value=\"0\"/>\n";
+ echo "<input name=\"$name\" type=\"checkbox\" value=\"1\" ".$window->$name." alt=\"$name\" />\n";
+ $stringname = "str$name";
+ echo $$stringname."<br />\n";
+ }
+ ?>
+ <script type="text/javascript">
+ lockoptions('form','popup[1]', popupitems);
+ </script>
+ </blockquote>
+ </td>
+ </tr>
+ </table>
+ </div>
+ <script language="javascript" type="text/javascript">
+ showhide('advancedsettings', true);
+ showhide('windowsettings', true);
+ </script>
+ </td>
+ </tr>
+ </table>
+ <input type="hidden" name="datadir" value="<?php p($form->datadir) ?>" />
+ <input type="hidden" name="pkgtype" value="<?php p($form->pkgtype) ?>" />
+ <input type="hidden" name="launch" value="<?php p($form->launch) ?>" />
+ <input type="hidden" name="parse" value="0" />
+ <?php
+ $scorms = get_all_instances_in_course('scorm', $course);
+ $coursescorm = current($scorms);
+ if (($course->format == 'scorm') && ((count($scorms) == 0) || ($form->instance == $coursescorm->id))) {
+ ?>
+ <input type="hidden" name="redirect" value="yes" />
+ <input type="hidden" name="redirecturl" value="../course/view.php?id=<?php p($form->course) ?>" />
+ <?php
+ }
+ ?>
+ <input type="hidden" name="course" value="<?php p($form->course) ?>" />
+ <input type="hidden" name="sesskey" value="<?php p($form->sesskey) ?>" />
+ <input type="hidden" name="section" value="<?php p($form->section) ?>" />
+ <input type="hidden" name="module" value="<?php p($form->module) ?>" />
+ <input type="hidden" name="mode" value="<?php p($form->mode) ?>" />
+ <input type="hidden" name="coursemodule" value="<?php p($form->coursemodule) ?>" />
+ <input type="hidden" name="modulename" value="<?php p($form->modulename) ?>" />
+ <input type="hidden" name="instance" value="<?php p($form->instance) ?>" />
+ <center>
+ <input type="submit" value="<?php print_string('savechanges') ?>"/>
+ <input type="button" name="cancel" value="<?php print_string('cancel') ?>" onclick="document.location='view.php?id=<?php echo $form->course ?>'" />
+ </center>
+</form>
-<?php \r
-\r
-// Cac ham danh cho viec thuc thi Sequencing\r
-// --------Ket thuc cac ham danh cho viec thuc thi Sequencing ------------\r
-\r
-// Cac ham danh cho viec thuc thi Rollup\r
-\r
-//-----------------------------------------------------\r
-function scorm_rollup_updatestatus($scormid,$scoidchild, $userid)\r
-{\r
- //$f = "D:\\test.txt";\r
- //@$ft = fopen($f,"a");\r
- //fwrite($ft,"\n >>>>> SCO goi Rollup la ".$scoidchild);\r
- $scochild = get_record("scorm_scoes","id",$scoidchild);\r
- $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
- //Danh sach cac con cua cha\r
- $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");\r
- //Lay gia tri last attempt\r
- //fwrite($ft,"\n >>>>> Bat dau xu ly Rollup SCO cha ".$scoparent->id);\r
- $attempt = scorm_get_last_attempt($scormid,$userid);\r
- \r
- if(!empty($scoparent)){\r
- $scoid = $scoparent->id;\r
- $rolluprules = get_record("scorm_sequencing_rolluprules","scormid",$scormid,"scoid",$scoid);\r
- if (!empty($rolluprules)){\r
- $idrolluprules = $rolluprules->id;\r
- $rules = get_records_select('scorm_sequencing_rolluprule','scoid ='.$scoid.' and rolluprulesid ='. $idrolluprules);\r
- \r
- foreach ($rules as $rule){\r
- $ruleid = $rule->id;\r
- $ruleConditions = get_record("scorm_sequencing_rollupruleconditions","scoid",$scoid,"rollupruleid",$ruleid); \r
- $idruleConditions = $ruleConditions->id;\r
- $conditions = get_records_select('scorm_sequencing_rolluprulecondition','scoid ='.$scoid.' and ruleconditionsid ='.$idruleConditions); \r
- \r
- //Truong hop 1: childactivitySet = all\r
- // conditioncombination = any\r
- if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='any')){\r
- foreach($conditions as $condition){\r
- $conditionOK = false; \r
- //Condition 1: condition = attempted operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien attempt \n");\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status != 'attempted'){\r
- //fwrite($ft,"\n >>>>> Co SCO con chua attempted \n");\r
- $conditionOK = false;\r
- }\r
- }\r
- }\r
- //Condition 2: condition = attempted operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien not attempt \n");\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status != 'notattempted'){\r
- $conditionOK = false;\r
- }\r
- }\r
- } \r
- //Condition 3: condition = satisfied operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->satisfied_status != 'satisfied'){\r
- $conditionOK = false;\r
- }\r
- }\r
- }\r
- //Condition 4: condition = satisfied operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->satisfied_status != 'notSatisfied'){\r
- $conditionOK = false;\r
- }\r
- }\r
- } \r
- //Condition 5: condition = completed operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status != 'completed'){\r
- $conditionOK = false;\r
- }\r
- }\r
- } \r
- //Condition 6: condition = completed operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status != 'notcompleted'){\r
- $conditionOK = false;\r
- }\r
- }\r
- } \r
- //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
- if ($conditionOK == true){\r
- if ($ruleConditions->rollupruleaction == 'completed')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed cho SCO ".$scoid);\r
- }\r
- if ($ruleConditions->rollupruleaction == 'satisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");\r
- } \r
- //echo "<script language='JavaScript'>";\r
- //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
- //echo "<script>";\r
- \r
- }\r
- }\r
- }\r
- //Ket thuc truong hop 1\r
- //Truong hop 2: childactivitySet = any\r
- // conditioncombination = any\r
- if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='any')){\r
- $conditionOK = false; \r
- foreach($conditions as $condition){\r
- //$conditionOK = false; \r
- //Condition 1: condition = attempted operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status = 'attempted'){\r
- $conditionOK = true;\r
- }\r
- }\r
- }\r
- //Condition 2: condition = attempted operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status = 'notattempted'){\r
- $conditionOK = true;\r
- }\r
- }\r
- } \r
- //Condition 3: condition = satisfied operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->satisfied_status = 'satisfied'){\r
- $conditionOK = true;\r
- }\r
- }\r
- }\r
- //Condition 4: condition = satisfied operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->satisfied_status = 'notSatisfied'){\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup voi notSatisfied\n");\r
- $conditionOK = true;\r
- }\r
- }\r
- } \r
- //Condition 5: condition = completed operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status = 'completed'){\r
- $conditionOK = true;\r
- }\r
- }\r
- } \r
- //Condition 6: condition = completed operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
- $conditionOK = false; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- if ($usertrack->attempt_status = 'notcompleted'){\r
- $conditionOK = true;\r
- }\r
- }\r
- } \r
- //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
- if ($conditionOK == true){\r
- if ($ruleConditions->rollupruleaction == 'completed')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'satisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");\r
- } \r
- //echo "<script language='JavaScript'>";\r
- //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
- //echo "<script>";\r
- \r
- }\r
- }\r
- }\r
- //Ket thuc truong hop 2\r
- //Truong hop 3: childactivitySet = any\r
- // conditioncombination = all\r
- if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='all')){\r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- $conditionOK = true; \r
- foreach($conditions as $condition){\r
- //Condition 1: condition = attempted operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'attempted'){\r
- $conditionOK = false;\r
- }\r
- }\r
- //Condition 2: condition = attempted operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notattempted'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 3: condition = satisfied operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'satisfied'){\r
- $conditionOK = false;\r
- }\r
- }\r
- //Condition 4: condition = satisfied operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notSatisfied'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 5: condition = completed operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'completed'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 6: condition = completed operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notcompleted'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
- }\r
- }\r
- if ($conditionOK == true){\r
- if ($ruleConditions->rollupruleaction == 'completed')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'satisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");\r
- } \r
- //echo "<script language='JavaScript'>";\r
- //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
- //echo "<script>";\r
- \r
- } \r
- }\r
- //Ket thuc truong hop 3\r
- //Truong hop 4: childactivitySet = all\r
- // conditioncombination = all\r
- if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='all')){\r
- $conditionOK = true; \r
- foreach ($scochildren as $sco){\r
- $usertrack = scorm_get_tracks($sco->id,$userid);\r
- foreach($conditions as $condition){\r
- //Condition 1: condition = attempted operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'attempted'){\r
- $conditionOK = false;\r
- }\r
- }\r
- //Condition 2: condition = attempted operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'attempted') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notattempted'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 3: condition = satisfied operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'satisfied'){\r
- $conditionOK = false;\r
- }\r
- }\r
- //Condition 4: condition = satisfied operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'satisfied') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notSatisfied'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 5: condition = completed operator = 'noOp'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='noOp')){\r
- if ($usertrack->attempt_status != 'completed'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Condition 6: condition = completed operator = 'not'\r
- // Thuc hien rollupaction \r
- if (($condition->condition == 'completed') && ($condition->operator=='not')){\r
- if ($usertrack->attempt_status != 'notcompleted'){\r
- $conditionOK = false;\r
- }\r
- } \r
- //Neu dieu kien van dung sau khi xem xet thi thuc hien action\r
- }\r
- }\r
- if ($conditionOK == true){\r
- if ($ruleConditions->rollupruleaction == 'completed')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'satisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");\r
- }\r
- if ($ruleConditions->rollupruleaction == 'notSatisfied')\r
- {\r
- scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');\r
- //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");\r
- } \r
- //echo "<script language='JavaScript'>";\r
- //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";\r
- //echo "<script>";\r
- \r
- } \r
- }\r
- //Ket thuc truong hop 4 \r
- } \r
- }\r
- \r
- //Thuc hien de qui cho Rollup voi cac muc cha\r
- $scograndparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scoparent->parent);\r
- if (!empty($scograndparent)){\r
- //fwrite($ft,"\n >>>>> Quay lui Rollup SCO ".$scoparent->id);\r
- scorm_rollup_updatestatus($scormid,$scoparent->id, $userid);\r
- }\r
- }\r
-}\r
-\r
-// --------Ket thuc cac ham danh cho viec thuc thi Rollup -------\r
-\r
-//---------Thuc hien sequencing rule -----------------\r
-function scorm_sequecingrule_implement($scormid,$scoidchild, $userid)\r
-{\r
- $sequencingResult->rule = ''; //Rule co 3 truong hop exit, pre va post\r
- $sequencingResult->action = '';\r
- \r
- \r
- $f = "D:\\test.txt";\r
- @$ft = fopen($f,"a");\r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing \n");\r
-\r
- $scochild = get_record("scorm_scoes","id",$scoidchild);\r
- $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
- //Danh sach cac con cua cha\r
- $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");\r
- //Lay gia tri last attempt\r
- \r
- $attempt = scorm_get_last_attempt($scormid,$userid);\r
- \r
- if(!empty($scoparent)){\r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Parent\n");\r
- \r
- $scoid = $scoparent->id;\r
- //Lay trang thai cua SCO cha\r
- $usertrack = scorm_get_tracks($scoid,$userid);\r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing : id Parent ".$scoid); \r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing : usertrack ".$usertrack->status); \r
- $sequencingrules = get_records_select("scorm_sequencing_ruleconditions","scormid=".$scormid." and scoid=".$scoid);\r
- if (!empty($sequencingrules)){\r
- foreach($sequencingrules as $sequencingrule){\r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Sequencing o SCO".$sequencingrule->scoid); \r
- \r
- $idsequencingrule = $sequencingrule->id;\r
- $ruleconditions = get_records_select('scorm_sequencing_rulecondition','scoid ='.$scoid.' and ruleconditionsid ='. $idsequencingrule);\r
- \r
- $conditionOK = true;\r
- //Truong hop 1: conditioncombination = all \r
- if ($sequencingrule->conditioncombination =='all'){\r
- //fwrite($ft,"\n >>>>> Kiem tra Sequencing :conditioncombination la all \n"); \r
- $conditionOK = true;\r
- //fwrite($ft,"\n >>>>> Usertrack->status la: ".$usertrack->status);\r
- foreach ($ruleconditions as $rulecondition){\r
- //Neu co mot dieu kien khong thoa man thi se khong dung\r
- if (($rulecondition->condition != $usertrack->status)&&($rulecondition->condition != $usertrack->success_status)&&($rulecondition->condition != $usertrack->satisfied_status)){\r
- $conditionOK = false; \r
- }\r
- } \r
- }\r
- //Truong hop 2: conditioncombination = any \r
- if ($sequencingrule->conditioncombination =='any'){\r
- $conditionOK = false; \r
- foreach ($ruleconditions as $rulecondition){\r
- //Neu co mot dieu kien thoa man thi se dung\r
- if (($rulecondition->condition == $usertrack->status) || ($rulecondition->condition == $usertrack->success_status) || ($rulecondition->condition == $usertrack->satisfied_status) ){\r
- $conditionOK = true; \r
- }\r
- } \r
- }\r
- \r
- //fwrite($ft,"\n >>>>> Gia tri conditionOK sau khi kiem tra dk la: ".$conditionOK);\r
- //Neu dieu kien van dung thi thuc hien Action \r
- if ($conditionOK == true){\r
- //fwrite($ft,"\n >>>>> Dieu kien Sequencing OK..Thuc hien Action \n"); \r
- //Truong hop 1: ExitAction la Exit\r
- if ($sequencingrule->exitconditionruleaction=='exit')\r
- {\r
- //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien exit \n");\r
- echo "<script language='JavaScript'>";\r
- echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh EXIT');";\r
- echo "</script>";\r
- $sequencingResult->rule = 'exit';\r
- $sequencingResult->action = 'exit'; \r
- }\r
- if ($sequencingrule->preconditionruleaction=='disabled')\r
- {\r
- //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien disable \n");\r
- echo "<script language='JavaScript'>";\r
- echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh Disable');";\r
- echo "</script>"; \r
- $sequencingResult->rule = 'pre';\r
- $sequencingResult->action = 'disable'; \r
- \r
- } \r
- \r
- }\r
- }\r
- }\r
- }\r
- return $sequencingResult;\r
-}\r
-\r
-function get_sco_after_exit($scoid,$scormid){\r
- $scochild = get_record("scorm_scoes","id",$scoid);\r
- $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);\r
- $exitscoid = $scoid++;\r
- $exitscochild = get_record("scorm_scoes","id",$exitscoid,"scorm",$scormid);\r
- if (empty($exitscochild)){\r
- //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung\r
- return 0;\r
- }\r
- else{\r
- $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);\r
- //Neu chua ra khoi activity do thi tiep tuc\r
- while ($exitscoparent->id == $scoparent->id){\r
- $exitscoid++;\r
- $exitscochild = get_record("scorm_scoes","id",$exitscoid);\r
- if (empty($exitscochild)){\r
- //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung\r
- return 0;\r
- }\r
- else{\r
- $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);\r
- }\r
- }\r
- }\r
- return $exitscoid; \r
-}\r
-\r
-?>\r
+<?php
+
+// Cac ham danh cho viec thuc thi Sequencing
+// --------Ket thuc cac ham danh cho viec thuc thi Sequencing ------------
+
+// Cac ham danh cho viec thuc thi Rollup
+
+//-----------------------------------------------------
+function scorm_rollup_updatestatus($scormid,$scoidchild, $userid)
+{
+ //$f = "D:\\test.txt";
+ //@$ft = fopen($f,"a");
+ //fwrite($ft,"\n >>>>> SCO goi Rollup la ".$scoidchild);
+ $scochild = get_record("scorm_scoes","id",$scoidchild);
+ $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+ //Danh sach cac con cua cha
+ $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");
+ //Lay gia tri last attempt
+ //fwrite($ft,"\n >>>>> Bat dau xu ly Rollup SCO cha ".$scoparent->id);
+ $attempt = scorm_get_last_attempt($scormid,$userid);
+
+ if(!empty($scoparent)){
+ $scoid = $scoparent->id;
+ $rolluprules = get_record("scorm_sequencing_rolluprules","scormid",$scormid,"scoid",$scoid);
+ if (!empty($rolluprules)){
+ $idrolluprules = $rolluprules->id;
+ $rules = get_records_select('scorm_sequencing_rolluprule','scoid ='.$scoid.' and rolluprulesid ='. $idrolluprules);
+
+ foreach ($rules as $rule){
+ $ruleid = $rule->id;
+ $ruleConditions = get_record("scorm_sequencing_rollupruleconditions","scoid",$scoid,"rollupruleid",$ruleid);
+ $idruleConditions = $ruleConditions->id;
+ $conditions = get_records_select('scorm_sequencing_rolluprulecondition','scoid ='.$scoid.' and ruleconditionsid ='.$idruleConditions);
+
+ //Truong hop 1: childactivitySet = all
+ // conditioncombination = any
+ if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='any')){
+ foreach($conditions as $condition){
+ $conditionOK = false;
+ //Condition 1: condition = attempted operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien attempt \n");
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status != 'attempted'){
+ //fwrite($ft,"\n >>>>> Co SCO con chua attempted \n");
+ $conditionOK = false;
+ }
+ }
+ }
+ //Condition 2: condition = attempted operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ //fwrite($ft,"\n >>>>> Xu ly Rollup voi dieu kien not attempt \n");
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status != 'notattempted'){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Condition 3: condition = satisfied operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->satisfied_status != 'satisfied'){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Condition 4: condition = satisfied operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->satisfied_status != 'notSatisfied'){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Condition 5: condition = completed operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status != 'completed'){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Condition 6: condition = completed operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='not')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status != 'notcompleted'){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+ if ($conditionOK == true){
+ if ($ruleConditions->rollupruleaction == 'completed')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed cho SCO ".$scoid);
+ }
+ if ($ruleConditions->rollupruleaction == 'satisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'notSatisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");
+ }
+ //echo "<script language='JavaScript'>";
+ //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+ //echo "<script>";
+
+ }
+ }
+ }
+ //Ket thuc truong hop 1
+ //Truong hop 2: childactivitySet = any
+ // conditioncombination = any
+ if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='any')){
+ $conditionOK = false;
+ foreach($conditions as $condition){
+ //$conditionOK = false;
+ //Condition 1: condition = attempted operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status = 'attempted'){
+ $conditionOK = true;
+ }
+ }
+ }
+ //Condition 2: condition = attempted operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status = 'notattempted'){
+ $conditionOK = true;
+ }
+ }
+ }
+ //Condition 3: condition = satisfied operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->satisfied_status = 'satisfied'){
+ $conditionOK = true;
+ }
+ }
+ }
+ //Condition 4: condition = satisfied operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->satisfied_status = 'notSatisfied'){
+ //fwrite($ft,"\n >>>>> Xu ly Rollup voi notSatisfied\n");
+ $conditionOK = true;
+ }
+ }
+ }
+ //Condition 5: condition = completed operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status = 'completed'){
+ $conditionOK = true;
+ }
+ }
+ }
+ //Condition 6: condition = completed operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='not')){
+ $conditionOK = false;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ if ($usertrack->attempt_status = 'notcompleted'){
+ $conditionOK = true;
+ }
+ }
+ }
+ //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+ if ($conditionOK == true){
+ if ($ruleConditions->rollupruleaction == 'completed')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'satisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'notSatisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");
+ }
+ //echo "<script language='JavaScript'>";
+ //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+ //echo "<script>";
+
+ }
+ }
+ }
+ //Ket thuc truong hop 2
+ //Truong hop 3: childactivitySet = any
+ // conditioncombination = all
+ if (($rule->childactivityset == 'any') && ($ruleConditions->conditioncombination=='all')){
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ $conditionOK = true;
+ foreach($conditions as $condition){
+ //Condition 1: condition = attempted operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'attempted'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 2: condition = attempted operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notattempted'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 3: condition = satisfied operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'satisfied'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 4: condition = satisfied operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notSatisfied'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 5: condition = completed operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'completed'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 6: condition = completed operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notcompleted'){
+ $conditionOK = false;
+ }
+ }
+ //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+ }
+ }
+ if ($conditionOK == true){
+ if ($ruleConditions->rollupruleaction == 'completed')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'satisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'notSatisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");
+ }
+ //echo "<script language='JavaScript'>";
+ //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+ //echo "<script>";
+
+ }
+ }
+ //Ket thuc truong hop 3
+ //Truong hop 4: childactivitySet = all
+ // conditioncombination = all
+ if (($rule->childactivityset == 'all') && ($ruleConditions->conditioncombination=='all')){
+ $conditionOK = true;
+ foreach ($scochildren as $sco){
+ $usertrack = scorm_get_tracks($sco->id,$userid);
+ foreach($conditions as $condition){
+ //Condition 1: condition = attempted operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'attempted'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 2: condition = attempted operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'attempted') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notattempted'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 3: condition = satisfied operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'satisfied'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 4: condition = satisfied operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'satisfied') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notSatisfied'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 5: condition = completed operator = 'noOp'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='noOp')){
+ if ($usertrack->attempt_status != 'completed'){
+ $conditionOK = false;
+ }
+ }
+ //Condition 6: condition = completed operator = 'not'
+ // Thuc hien rollupaction
+ if (($condition->condition == 'completed') && ($condition->operator=='not')){
+ if ($usertrack->attempt_status != 'notcompleted'){
+ $conditionOK = false;
+ }
+ }
+ //Neu dieu kien van dung sau khi xem xet thi thuc hien action
+ }
+ }
+ if ($conditionOK == true){
+ if ($ruleConditions->rollupruleaction == 'completed')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.completion_status','completed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi completed\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'satisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','passed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi satisfied\n");
+ }
+ if ($ruleConditions->rollupruleaction == 'notSatisfied')
+ {
+ scorm_insert_track($userid,$scormid,$scoid,$attempt,'cmi.success_status','failed');
+ //fwrite($ft,"\n >>>>> Xu ly Rollup thanh cong voi notSatisfied\n");
+ }
+ //echo "<script language='JavaScript'>";
+ //echo "alert('Thuc hien rollup. Trang thai ".$scoparent->identifier." la hoan thanh voi userid".$userid."');";
+ //echo "<script>";
+
+ }
+ }
+ //Ket thuc truong hop 4
+ }
+ }
+
+ //Thuc hien de qui cho Rollup voi cac muc cha
+ $scograndparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scoparent->parent);
+ if (!empty($scograndparent)){
+ //fwrite($ft,"\n >>>>> Quay lui Rollup SCO ".$scoparent->id);
+ scorm_rollup_updatestatus($scormid,$scoparent->id, $userid);
+ }
+ }
+}
+
+// --------Ket thuc cac ham danh cho viec thuc thi Rollup -------
+
+//---------Thuc hien sequencing rule -----------------
+function scorm_sequecingrule_implement($scormid,$scoidchild, $userid)
+{
+ $sequencingResult->rule = ''; //Rule co 3 truong hop exit, pre va post
+ $sequencingResult->action = '';
+
+
+ $f = "D:\\test.txt";
+ @$ft = fopen($f,"a");
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing \n");
+
+ $scochild = get_record("scorm_scoes","id",$scoidchild);
+ $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+ //Danh sach cac con cua cha
+ $scochildren = get_records_select("scorm_scoes","scorm =".$scormid." and parent ='".$scoparent->identifier."'");
+ //Lay gia tri last attempt
+
+ $attempt = scorm_get_last_attempt($scormid,$userid);
+
+ if(!empty($scoparent)){
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Parent\n");
+
+ $scoid = $scoparent->id;
+ //Lay trang thai cua SCO cha
+ $usertrack = scorm_get_tracks($scoid,$userid);
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing : id Parent ".$scoid);
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing : usertrack ".$usertrack->status);
+ $sequencingrules = get_records_select("scorm_sequencing_ruleconditions","scormid=".$scormid." and scoid=".$scoid);
+ if (!empty($sequencingrules)){
+ foreach($sequencingrules as $sequencingrule){
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing : Co Sequencing o SCO".$sequencingrule->scoid);
+
+ $idsequencingrule = $sequencingrule->id;
+ $ruleconditions = get_records_select('scorm_sequencing_rulecondition','scoid ='.$scoid.' and ruleconditionsid ='. $idsequencingrule);
+
+ $conditionOK = true;
+ //Truong hop 1: conditioncombination = all
+ if ($sequencingrule->conditioncombination =='all'){
+ //fwrite($ft,"\n >>>>> Kiem tra Sequencing :conditioncombination la all \n");
+ $conditionOK = true;
+ //fwrite($ft,"\n >>>>> Usertrack->status la: ".$usertrack->status);
+ foreach ($ruleconditions as $rulecondition){
+ //Neu co mot dieu kien khong thoa man thi se khong dung
+ if (($rulecondition->condition != $usertrack->status)&&($rulecondition->condition != $usertrack->success_status)&&($rulecondition->condition != $usertrack->satisfied_status)){
+ $conditionOK = false;
+ }
+ }
+ }
+ //Truong hop 2: conditioncombination = any
+ if ($sequencingrule->conditioncombination =='any'){
+ $conditionOK = false;
+ foreach ($ruleconditions as $rulecondition){
+ //Neu co mot dieu kien thoa man thi se dung
+ if (($rulecondition->condition == $usertrack->status) || ($rulecondition->condition == $usertrack->success_status) || ($rulecondition->condition == $usertrack->satisfied_status) ){
+ $conditionOK = true;
+ }
+ }
+ }
+
+ //fwrite($ft,"\n >>>>> Gia tri conditionOK sau khi kiem tra dk la: ".$conditionOK);
+ //Neu dieu kien van dung thi thuc hien Action
+ if ($conditionOK == true){
+ //fwrite($ft,"\n >>>>> Dieu kien Sequencing OK..Thuc hien Action \n");
+ //Truong hop 1: ExitAction la Exit
+ if ($sequencingrule->exitconditionruleaction=='exit')
+ {
+ //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien exit \n");
+ echo "<script language='JavaScript'>";
+ echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh EXIT');";
+ echo "</script>";
+ $sequencingResult->rule = 'exit';
+ $sequencingResult->action = 'exit';
+ }
+ if ($sequencingrule->preconditionruleaction=='disabled')
+ {
+ //fwrite($ft,"\n >>>>> Xu ly Sequencing thanh cong -- Thuc hien su kien disable \n");
+ echo "<script language='JavaScript'>";
+ echo "alert('Thuc hien sequen. Do Trang thai ".$scoparent->identifier." la hoan thanh. Tien hanh Disable');";
+ echo "</script>";
+ $sequencingResult->rule = 'pre';
+ $sequencingResult->action = 'disable';
+
+ }
+
+ }
+ }
+ }
+ }
+ return $sequencingResult;
+}
+
+function get_sco_after_exit($scoid,$scormid){
+ $scochild = get_record("scorm_scoes","id",$scoid);
+ $scoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$scochild->parent);
+ $exitscoid = $scoid++;
+ $exitscochild = get_record("scorm_scoes","id",$exitscoid,"scorm",$scormid);
+ if (empty($exitscochild)){
+ //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung
+ return 0;
+ }
+ else{
+ $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);
+ //Neu chua ra khoi activity do thi tiep tuc
+ while ($exitscoparent->id == $scoparent->id){
+ $exitscoid++;
+ $exitscochild = get_record("scorm_scoes","id",$exitscoid);
+ if (empty($exitscochild)){
+ //Da ra ngoai vung scoid. Hay day chinh la sco cuoi cung
+ return 0;
+ }
+ else{
+ $exitscoparent = get_record("scorm_scoes","scorm",$scormid,"identifier",$exitscochild->parent);
+ }
+ }
+ }
+ return $exitscoid;
+}
+
+?>
-.structlist {\r
- list-style-type: none;\r
- white-space: nowrap;\r
- font-size: small;\r
-}\r
-.orgtitle {\r
- font-weight: bold;\r
- font-size: small;\r
-}\r
-.mod-scorm .top {\r
- vertical-align: top;\r
-}\r
-.mod-scorm .left {\r
- text-align: left;\r
-}\r
-.mod-scorm .center {\r
- text-align: center;\r
-}\r
-.mod-scorm .right {\r
- text-align: right;\r
-}\r
-.mod-scorm .scoframe {\r
-\r
-}\r
-\r
-#mod-scorm-player #scormpage {\r
- position: relative;\r
- width: 100%;\r
-}\r
-#mod-scorm-player #tocbox {\r
- position: absolute;\r
- left: 0px;\r
- top: 0px;\r
- width: 19%;\r
-}\r
-#mod-scorm-player #tochead {\r
- text-align: center;\r
- font-weight: bold;\r
-}\r
-#mod-scorm-player #scormbox {\r
- position: absolute;\r
- right: 0px;\r
- top: 0px;\r
-}\r
-#mod-scorm-player .toc {\r
- width: 80%; \r
- margin-left: 20%; \r
-}\r
-#mod-scorm-player .no-toc {\r
- width: 100%;\r
-}\r
-#mod-scorm-player #scormobject {\r
- /* border: 1px solid black; */\r
-}\r
-#mod-scorm-player #scormtop {\r
- position: relative;\r
- width: 100%;\r
- height: 30px;\r
-}\r
-#mod-scorm-player #scormbrowse {\r
- position: absolute;\r
- left: 5px;\r
- top: 0px;\r
-}\r
-#mod-scorm-player #scormnav {\r
- position: absolute;\r
- right: 5px;\r
- top: 0px;\r
-}\r
-#mod-scorm-player .structurelist {\r
- list-style-type: none;\r
- text-indent:-4ex;\r
- font-size: small;\r
-}\r
-\r
-#mod-scorm-view .structurehead {\r
- font-weight: bold;\r
- text-align: center;\r
-}\r
-#mod-scorm-view .structurelist {\r
- list-style-type: none;\r
- white-space: nowrap;\r
-}\r
+.structlist {
+ list-style-type: none;
+ white-space: nowrap;
+ font-size: small;
+}
+.orgtitle {
+ font-weight: bold;
+ font-size: small;
+}
+.mod-scorm .top {
+ vertical-align: top;
+}
+.mod-scorm .left {
+ text-align: left;
+}
+.mod-scorm .center {
+ text-align: center;
+}
+.mod-scorm .right {
+ text-align: right;
+}
+.mod-scorm .scoframe {
+
+}
+
+#mod-scorm-player #scormpage {
+ position: relative;
+ width: 100%;
+}
+#mod-scorm-player #tocbox {
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ width: 19%;
+}
+#mod-scorm-player #tochead {
+ text-align: center;
+ font-weight: bold;
+}
+#mod-scorm-player #scormbox {
+ position: absolute;
+ right: 0px;
+ top: 0px;
+}
+#mod-scorm-player .toc {
+ width: 80%;
+ margin-left: 20%;
+}
+#mod-scorm-player .no-toc {
+ width: 100%;
+}
+#mod-scorm-player #scormobject {
+ /* border: 1px solid black; */
+}
+#mod-scorm-player #scormtop {
+ position: relative;
+ width: 100%;
+ height: 30px;
+}
+#mod-scorm-player #scormbrowse {
+ position: absolute;
+ left: 5px;
+ top: 0px;
+}
+#mod-scorm-player #scormnav {
+ position: absolute;
+ right: 5px;
+ top: 0px;
+}
+#mod-scorm-player .structurelist {
+ list-style-type: none;
+ text-indent:-4ex;
+ font-size: small;
+}
+
+#mod-scorm-view .structurehead {
+ font-weight: bold;
+ text-align: center;
+}
+#mod-scorm-view .structurelist {
+ list-style-type: none;
+ white-space: nowrap;
+}
-<?php\r
- require_once('../../config.php');\r
- require_once('locallib.php');\r
-\r
- $id = required_param('id', PARAM_INT); // course ID\r
- $scormid = required_param('scorm', PARAM_INT); // scorm ID\r
- $scoid = required_param('sco', PARAM_INT); // suspend sco ID\r
- $userid = required_param('userid', PARAM_INT); // user ID\r
-\r
- $attempt = scorm_get_last_attempt($scormid,$userid);\r
- $statistic = get_record('scorm_statistic',"scormid",$scormid,"userid",$userid);\r
- $statisticInput->accesstime = $statistic->accesstime;\r
- $statisticInput->durationtime = $statistic->durationtime + time()- $statistic->accesstime;\r
- $statisticInput->status = 'suspend';\r
- $statisticInput->attemptnumber = $attempt;\r
- $statisticInput->scormid = $statistic->scormid;\r
- $statisticInput->userid = $statistic->userid; \r
- $statisticid = scorm_insert_statistic($statisticInput);\r
-\r
- $result = scorm_insert_trackmodel($userid, $scormid, $scoid,$attempt);\r
- if ($result) {\r
- echo "<script language='Javascript' type='text/javascript'>";\r
- echo "location.href='".$CFG->wwwroot." /course/view.php?id=".$id."';"; \r
- echo "</script>";\r
- } else {\r
- echo "Suspend failed";\r
- }\r
-?>\r
-\r
+<?php
+ require_once('../../config.php');
+ require_once('locallib.php');
+
+ $id = required_param('id', PARAM_INT); // course ID
+ $scormid = required_param('scorm', PARAM_INT); // scorm ID
+ $scoid = required_param('sco', PARAM_INT); // suspend sco ID
+ $userid = required_param('userid', PARAM_INT); // user ID
+
+ $attempt = scorm_get_last_attempt($scormid,$userid);
+ $statistic = get_record('scorm_statistic',"scormid",$scormid,"userid",$userid);
+ $statisticInput->accesstime = $statistic->accesstime;
+ $statisticInput->durationtime = $statistic->durationtime + time()- $statistic->accesstime;
+ $statisticInput->status = 'suspend';
+ $statisticInput->attemptnumber = $attempt;
+ $statisticInput->scormid = $statistic->scormid;
+ $statisticInput->userid = $statistic->userid;
+ $statisticid = scorm_insert_statistic($statisticInput);
+
+ $result = scorm_insert_trackmodel($userid, $scormid, $scoid,$attempt);
+ if ($result) {
+ echo "<script language='Javascript' type='text/javascript'>";
+ echo "location.href='".$CFG->wwwroot." /course/view.php?id=".$id."';";
+ echo "</script>";
+ } else {
+ echo "Suspend failed";
+ }
+?>
+
-# phpMyAdmin MySQL-Dump\r
-# version 2.2.1\r
-# http://phpwizard.net/phpMyAdmin/\r
-# http://phpmyadmin.sourceforge.net/ (download page)\r
-#\r
-# Host: localhost\r
-# Generation Time: Nov 14, 2001 at 04:39 PM\r
-# Server version: 3.23.36\r
-# PHP Version: 4.0.6\r
-# Database : `moodle`\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey`\r
-#\r
-\r
-CREATE TABLE prefix_survey (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- course int(10) unsigned NOT NULL default '0',\r
- template int(10) unsigned NOT NULL default '0',\r
- days smallint(6) NOT NULL default '0',\r
- timecreated int(10) unsigned NOT NULL default '0',\r
- timemodified int(10) unsigned NOT NULL default '0',\r
- name varchar(255) NOT NULL default '',\r
- intro text NOT NULL default '',\r
- questions varchar(255) NOT NULL default '',\r
- PRIMARY KEY (id), \r
- KEY `course` (`course`)\r
-) TYPE=MyISAM COMMENT='all surveys';\r
-\r
-#\r
-# Dumping data for table `survey`\r
-#\r
-\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (1, 0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (2, 0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (3, 0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (4, 0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');\r
-INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (5, 0, 0, 0, 985017600, 985017600, 'ciqname', 'ciqintro', '69,70,71,72,73');\r
-\r
-\r
-\r
-#\r
-# Table structure for table `survey_analysis`\r
-#\r
-\r
-CREATE TABLE prefix_survey_analysis (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- survey int(10) unsigned NOT NULL default '0',\r
- userid int(10) unsigned NOT NULL default '0',\r
- notes text NOT NULL default '',\r
- PRIMARY KEY (id),\r
- UNIQUE KEY id (id),\r
- KEY survey (survey),\r
- KEY userid (userid)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_analysis`\r
-#\r
-\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey_answers`\r
-#\r
-\r
-CREATE TABLE prefix_survey_answers (\r
- id int(10) unsigned NOT NULL auto_increment,\r
- userid int(10) unsigned NOT NULL default '0',\r
- survey int(10) unsigned NOT NULL default '0',\r
- question int(10) unsigned NOT NULL default '0',\r
- time int(10) unsigned NOT NULL default '0',\r
- answer1 text NOT NULL default '',\r
- answer2 text NOT NULL default '',\r
- PRIMARY KEY (id),\r
- UNIQUE KEY id (id),\r
- KEY userid (userid),\r
- KEY survey (survey),\r
- KEY question (question)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_answers`\r
-#\r
-\r
-# --------------------------------------------------------\r
-\r
-#\r
-# Table structure for table `survey_questions`\r
-#\r
-\r
-CREATE TABLE `prefix_survey_questions` (\r
- `id` int(10) unsigned NOT NULL auto_increment,\r
- `text` varchar(255) NOT NULL default '',\r
- `shorttext` varchar(30) NOT NULL default '',\r
- `multi` varchar(100) NOT NULL default '',\r
- `intro` varchar(50) NOT NULL default '',\r
- `type` tinyint(3) NOT NULL default '0',\r
- `options` text,\r
- PRIMARY KEY (`id`)\r
-) TYPE=MyISAM;\r
-\r
-#\r
-# Dumping data for table `survey_questions`\r
-#\r
-\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (1, 'colles1', 'colles1short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (2, 'colles2', 'colles2short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (3, 'colles3', 'colles3short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (4, 'colles4', 'colles4short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (5, 'colles5', 'colles5short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (6, 'colles6', 'colles6short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (7, 'colles7', 'colles7short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (8, 'colles8', 'colles8short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (9, 'colles9', 'colles9short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (10, 'colles10', 'colles10short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (11, 'colles11', 'colles11short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (12, 'colles12', 'colles12short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (13, 'colles13', 'colles13short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (14, 'colles14', 'colles14short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (15, 'colles15', 'colles15short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (16, 'colles16', 'colles16short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (17, 'colles17', 'colles17short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (18, 'colles18', 'colles18short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (19, 'colles19', 'colles19short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (20, 'colles20', 'colles20short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (21, 'colles21', 'colles21short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (22, 'colles22', 'colles22short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (23, 'colles23', 'colles23short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (24, 'colles24', 'colles24short', '', '', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (25, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (26, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (27, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (28, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (29, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (30, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (31, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (32, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (33, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (34, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (35, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (36, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (37, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (38, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (39, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (40, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (41, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (42, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (43, 'howlong', '', '', '', 1, 'howlongoptions');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (44, 'othercomments', '', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (64, 'attls20', 'attls20short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (58, 'attls14', 'attls14short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (59, 'attls15', 'attls15short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (60, 'attls16', 'attls16short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (61, 'attls17', 'attls17short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (62, 'attls18', 'attls18short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (63, 'attls19', 'attls19short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (56, 'attls12', 'attls12short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (57, 'attls13', 'attls13short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (55, 'attls11', 'attls11short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (54, 'attls10', 'attls10short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (53, 'attls9', 'attls9short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (52, 'attls8', 'attls8short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (51, 'attls7', 'attls7short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (50, 'attls6', 'attls6short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (49, 'attls5', 'attls5short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (48, 'attls4', 'attls4short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (47, 'attls3', 'attls3short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (45, 'attls1', 'attls1short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (46, 'attls2', 'attls2short', '', '', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (65, 'attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (67, 'attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (68, 'attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');\r
-\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (69, 'ciq1', 'ciq1short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (70, 'ciq2', 'ciq2short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (71, 'ciq3', 'ciq3short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (72, 'ciq4', 'ciq4short', '', '', 0, '');\r
-INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (73, 'ciq5', 'ciq5short', '', '', 0, '');\r
-\r
-\r
-#\r
-# Dumping data for table `log_display`\r
-#\r
-\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'add', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'update', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');\r
+# phpMyAdmin MySQL-Dump
+# version 2.2.1
+# http://phpwizard.net/phpMyAdmin/
+# http://phpmyadmin.sourceforge.net/ (download page)
+#
+# Host: localhost
+# Generation Time: Nov 14, 2001 at 04:39 PM
+# Server version: 3.23.36
+# PHP Version: 4.0.6
+# Database : `moodle`
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey`
+#
+
+CREATE TABLE prefix_survey (
+ id int(10) unsigned NOT NULL auto_increment,
+ course int(10) unsigned NOT NULL default '0',
+ template int(10) unsigned NOT NULL default '0',
+ days smallint(6) NOT NULL default '0',
+ timecreated int(10) unsigned NOT NULL default '0',
+ timemodified int(10) unsigned NOT NULL default '0',
+ name varchar(255) NOT NULL default '',
+ intro text NOT NULL default '',
+ questions varchar(255) NOT NULL default '',
+ PRIMARY KEY (id),
+ KEY `course` (`course`)
+) TYPE=MyISAM COMMENT='all surveys';
+
+#
+# Dumping data for table `survey`
+#
+
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (1, 0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (2, 0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (3, 0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (4, 0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');
+INSERT INTO `prefix_survey` (`id`, `course`, `template`, `days`, `timecreated`, `timemodified`, `name`, `intro`, `questions`) VALUES (5, 0, 0, 0, 985017600, 985017600, 'ciqname', 'ciqintro', '69,70,71,72,73');
+
+
+
+#
+# Table structure for table `survey_analysis`
+#
+
+CREATE TABLE prefix_survey_analysis (
+ id int(10) unsigned NOT NULL auto_increment,
+ survey int(10) unsigned NOT NULL default '0',
+ userid int(10) unsigned NOT NULL default '0',
+ notes text NOT NULL default '',
+ PRIMARY KEY (id),
+ UNIQUE KEY id (id),
+ KEY survey (survey),
+ KEY userid (userid)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_analysis`
+#
+
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey_answers`
+#
+
+CREATE TABLE prefix_survey_answers (
+ id int(10) unsigned NOT NULL auto_increment,
+ userid int(10) unsigned NOT NULL default '0',
+ survey int(10) unsigned NOT NULL default '0',
+ question int(10) unsigned NOT NULL default '0',
+ time int(10) unsigned NOT NULL default '0',
+ answer1 text NOT NULL default '',
+ answer2 text NOT NULL default '',
+ PRIMARY KEY (id),
+ UNIQUE KEY id (id),
+ KEY userid (userid),
+ KEY survey (survey),
+ KEY question (question)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_answers`
+#
+
+# --------------------------------------------------------
+
+#
+# Table structure for table `survey_questions`
+#
+
+CREATE TABLE `prefix_survey_questions` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `text` varchar(255) NOT NULL default '',
+ `shorttext` varchar(30) NOT NULL default '',
+ `multi` varchar(100) NOT NULL default '',
+ `intro` varchar(50) NOT NULL default '',
+ `type` tinyint(3) NOT NULL default '0',
+ `options` text,
+ PRIMARY KEY (`id`)
+) TYPE=MyISAM;
+
+#
+# Dumping data for table `survey_questions`
+#
+
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (1, 'colles1', 'colles1short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (2, 'colles2', 'colles2short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (3, 'colles3', 'colles3short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (4, 'colles4', 'colles4short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (5, 'colles5', 'colles5short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (6, 'colles6', 'colles6short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (7, 'colles7', 'colles7short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (8, 'colles8', 'colles8short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (9, 'colles9', 'colles9short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (10, 'colles10', 'colles10short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (11, 'colles11', 'colles11short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (12, 'colles12', 'colles12short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (13, 'colles13', 'colles13short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (14, 'colles14', 'colles14short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (15, 'colles15', 'colles15short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (16, 'colles16', 'colles16short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (17, 'colles17', 'colles17short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (18, 'colles18', 'colles18short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (19, 'colles19', 'colles19short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (20, 'colles20', 'colles20short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (21, 'colles21', 'colles21short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (22, 'colles22', 'colles22short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (23, 'colles23', 'colles23short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (24, 'colles24', 'colles24short', '', '', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (25, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (26, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (27, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (28, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (29, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (30, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (31, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (32, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (33, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (34, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (35, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (36, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (37, 'collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (38, 'collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (39, 'collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (40, 'collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (41, 'collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (42, 'collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (43, 'howlong', '', '', '', 1, 'howlongoptions');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (44, 'othercomments', '', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (64, 'attls20', 'attls20short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (58, 'attls14', 'attls14short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (59, 'attls15', 'attls15short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (60, 'attls16', 'attls16short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (61, 'attls17', 'attls17short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (62, 'attls18', 'attls18short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (63, 'attls19', 'attls19short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (56, 'attls12', 'attls12short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (57, 'attls13', 'attls13short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (55, 'attls11', 'attls11short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (54, 'attls10', 'attls10short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (53, 'attls9', 'attls9short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (52, 'attls8', 'attls8short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (51, 'attls7', 'attls7short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (50, 'attls6', 'attls6short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (49, 'attls5', 'attls5short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (48, 'attls4', 'attls4short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (47, 'attls3', 'attls3short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (45, 'attls1', 'attls1short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (46, 'attls2', 'attls2short', '', '', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (65, 'attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (67, 'attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (68, 'attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');
+
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (69, 'ciq1', 'ciq1short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (70, 'ciq2', 'ciq2short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (71, 'ciq3', 'ciq3short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (72, 'ciq4', 'ciq4short', '', '', 0, '');
+INSERT INTO `prefix_survey_questions` (`id`, `text`, `shorttext`, `multi`, `intro`, `type`, `options`) VALUES (73, 'ciq5', 'ciq5short', '', '', 0, '');
+
+
+#
+# Dumping data for table `log_display`
+#
+
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'add', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'update', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');
-rem\r
-rem Table structure for table survey\r
-rem\r
-\r
-drop TABLE prefix_survey;\r
-CREATE TABLE prefix_survey (\r
- id number(10) primary key,\r
- course number(10) default '0' not null,\r
- template number(10) default '0' not null,\r
- days number(6) default '0' not null,\r
- timecreated number(10) default '0' not null,\r
- timemodified number(10) default '0' not null,\r
- name varchar2(255) default '' not null,\r
- intro varchar2(1024),\r
- questions varchar2(255) default NULL\r
-);\r
-\r
-drop sequence p_survey_seq;\r
-create sequence p_survey_seq;\r
-\r
-create or replace trigger p_survey_trig\r
- before insert on prefix_survey\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_survey_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-COMMENT on table prefix_survey is 'all surveys';\r
-\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');\r
-INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');\r
-\r
-select * from prefix_survey order by 1,2;\r
-\r
-rem\r
-rem Table structure for table survey_analysis\r
-rem\r
-\r
-drop TABLE prefix_survey_analysis;\r
-CREATE TABLE prefix_survey_analysis (\r
-id number(10) primary key,\r
-survey number(10) default '0' not null,\r
-userid number(10) default '0' not null,\r
-notes varchar2(1024) NOT NULL\r
-\r
-drop sequence p_survey_analysis_seq;\r
-create sequence p_survey_analysis_seq;\r
-\r
-create or replace trigger p_survey_analysis_trig\r
- before insert on prefix_survey_analysis\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_survey_analysis_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-);\r
-\r
-comment on table prefix_survey_analysis is 'Survey analysis';\r
-\r
-rem\r
-rem Dumping data for table survey_analysis\r
-rem\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table survey_answers\r
-rem\r
-\r
-drop TABLE prefix_survey_answers;\r
-CREATE TABLE prefix_survey_answers (\r
-id number(10) primary key,\r
-userid number(10) default '0' not null,\r
-survey number(10) default '0' not null,\r
-question number(10) default '0' not null,\r
-time number(10) default NULL,\r
-answer1 varchar2(255) default NULL,\r
-answer2 varchar2(255) default NULL\r
-);\r
-\r
-drop sequence p_survey_answers_seq;\r
-create sequence p_survey_answers_seq;\r
-\r
-create or replace trigger p_survey_answers_trig\r
-before insert on prefix_survey_answers\r
-referencing new as new_row\r
-for each row\r
-begin\r
- select p_survey_answers_seq.nextval into :new_row.id from dual;\r
-end;\r
-.\r
-/\r
-\r
-\r
-rem\r
-rem Dumping data for table survey_answers\r
-rem\r
-\r
-rem --------------------------------------------------------\r
-\r
-rem\r
-rem Table structure for table survey_questions\r
-rem\r
-\r
-drop TABLE prefix_survey_questions;\r
-CREATE TABLE prefix_survey_questions (\r
-id number(10) primary key,\r
-text varchar2(255) default '' not null,\r
-shorttext varchar2(30) default '' not null,\r
-multi varchar2(100) default '' not null,\r
-intro varchar2(50) default NULL,\r
-type number(3) default '0' not null,\r
-options varchar2(1024)\r
-);\r
-\r
-comment on table prefix_survey_questions is 'structure for survey_questions';\r
-\r
-drop sequence p_survey_questions_seq;\r
-create sequence p_survey_questions_seq;\r
-\r
-create or replace trigger p_survey_questions_trig\r
- before insert on prefix_survey_questions\r
- referencing new as new_row\r
- for each row\r
- begin\r
- select p_survey_questions_seq.nextval into :new_row.id from dual;\r
- end;\r
-.\r
-/\r
-\r
-rem\r
-rem Dumping data for table survey_questions\r
-rem\r
-\r
-INSERT INTO prefix_survey_questions ( text, shorttext, multi, intro, type, options) VALUES ('colles1', 'colles1short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles2', 'colles2short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles3', 'colles3short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles4', 'colles4short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles5', 'colles5short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles6', 'colles6short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles7', 'colles7short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles8', 'colles8short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles9', 'colles9short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles10', 'colles10short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles11', 'colles11short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles12', 'colles12short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles13', 'colles13short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles14', 'colles14short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles15', 'colles15short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles16', 'colles16short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles17', 'colles17short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles18', 'colles18short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles19', 'colles19short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles20', 'colles20short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles21', 'colles21short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles22', 'colles22short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles23', 'colles23short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles24', 'colles24short', '1', '1', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('howlong', '1', '1', '1', 1, 'howlongoptions');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('othercomments', '1', '1', '1', 0, '');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls20', 'attls20short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls14', 'attls14short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls15', 'attls15short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls16', 'attls16short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls17', 'attls17short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls18', 'attls18short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls19', 'attls19short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls12', 'attls12short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls13', 'attls13short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls11', 'attls11short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls10', 'attls10short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls9', 'attls9short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls8', 'attls8short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls7', 'attls7short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls6', 'attls6short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls5', 'attls5short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls4', 'attls4short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls3', 'attls3short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls1', 'attls1short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls2', 'attls2short', '1', '1', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');\r
-INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');\r
-\r
-rem select * from prefix_survey_questions where text like 'colles%' or text like 'attlsm%'\r
-\r
-col id format 99\r
-select * from prefix_survey_questions;\r
-\r
-\r
-rem\r
-rem Dumping data for table log_display\r
-rem\r
-\r
-delete from prefix_log_display where module = 'survey';\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');\r
-INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');\r
-select * from prefix_log_display where module = 'survey';\r
+rem
+rem Table structure for table survey
+rem
+
+drop TABLE prefix_survey;
+CREATE TABLE prefix_survey (
+ id number(10) primary key,
+ course number(10) default '0' not null,
+ template number(10) default '0' not null,
+ days number(6) default '0' not null,
+ timecreated number(10) default '0' not null,
+ timemodified number(10) default '0' not null,
+ name varchar2(255) default '' not null,
+ intro varchar2(1024),
+ questions varchar2(255) default NULL
+);
+
+drop sequence p_survey_seq;
+create sequence p_survey_seq;
+
+create or replace trigger p_survey_trig
+ before insert on prefix_survey
+ referencing new as new_row
+ for each row
+ begin
+ select p_survey_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+COMMENT on table prefix_survey is 'all surveys';
+
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesaname', 'collesaintro', '25,26,27,28,29,30,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collespname', 'collespintro', '31,32,33,34,35,36,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'collesapname', 'collesapintro', '37,38,39,40,41,42,43,44');
+INSERT INTO prefix_survey (course, template, days, timecreated, timemodified, name, intro, questions) VALUES (0, 0, 0, 985017600, 985017600, 'attlsname', 'attlsintro', '65,67,68');
+
+select * from prefix_survey order by 1,2;
+
+rem
+rem Table structure for table survey_analysis
+rem
+
+drop TABLE prefix_survey_analysis;
+CREATE TABLE prefix_survey_analysis (
+id number(10) primary key,
+survey number(10) default '0' not null,
+userid number(10) default '0' not null,
+notes varchar2(1024) NOT NULL
+
+drop sequence p_survey_analysis_seq;
+create sequence p_survey_analysis_seq;
+
+create or replace trigger p_survey_analysis_trig
+ before insert on prefix_survey_analysis
+ referencing new as new_row
+ for each row
+ begin
+ select p_survey_analysis_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+);
+
+comment on table prefix_survey_analysis is 'Survey analysis';
+
+rem
+rem Dumping data for table survey_analysis
+rem
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table survey_answers
+rem
+
+drop TABLE prefix_survey_answers;
+CREATE TABLE prefix_survey_answers (
+id number(10) primary key,
+userid number(10) default '0' not null,
+survey number(10) default '0' not null,
+question number(10) default '0' not null,
+time number(10) default NULL,
+answer1 varchar2(255) default NULL,
+answer2 varchar2(255) default NULL
+);
+
+drop sequence p_survey_answers_seq;
+create sequence p_survey_answers_seq;
+
+create or replace trigger p_survey_answers_trig
+before insert on prefix_survey_answers
+referencing new as new_row
+for each row
+begin
+ select p_survey_answers_seq.nextval into :new_row.id from dual;
+end;
+.
+/
+
+
+rem
+rem Dumping data for table survey_answers
+rem
+
+rem --------------------------------------------------------
+
+rem
+rem Table structure for table survey_questions
+rem
+
+drop TABLE prefix_survey_questions;
+CREATE TABLE prefix_survey_questions (
+id number(10) primary key,
+text varchar2(255) default '' not null,
+shorttext varchar2(30) default '' not null,
+multi varchar2(100) default '' not null,
+intro varchar2(50) default NULL,
+type number(3) default '0' not null,
+options varchar2(1024)
+);
+
+comment on table prefix_survey_questions is 'structure for survey_questions';
+
+drop sequence p_survey_questions_seq;
+create sequence p_survey_questions_seq;
+
+create or replace trigger p_survey_questions_trig
+ before insert on prefix_survey_questions
+ referencing new as new_row
+ for each row
+ begin
+ select p_survey_questions_seq.nextval into :new_row.id from dual;
+ end;
+.
+/
+
+rem
+rem Dumping data for table survey_questions
+rem
+
+INSERT INTO prefix_survey_questions ( text, shorttext, multi, intro, type, options) VALUES ('colles1', 'colles1short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles2', 'colles2short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles3', 'colles3short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles4', 'colles4short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles5', 'colles5short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles6', 'colles6short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles7', 'colles7short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles8', 'colles8short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles9', 'colles9short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles10', 'colles10short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles11', 'colles11short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles12', 'colles12short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ( 'colles13', 'colles13short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles14', 'colles14short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles15', 'colles15short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles16', 'colles16short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles17', 'colles17short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles18', 'colles18short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles19', 'colles19short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles20', 'colles20short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles21', 'colles21short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles22', 'colles22short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles23', 'colles23short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('colles24', 'colles24short', '1', '1', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 1, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 2, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm1', 'collesm1short', '1,2,3,4', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm2', 'collesm2short', '5,6,7,8', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm3', 'collesm3short', '9,10,11,12', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm4', 'collesm4short', '13,14,15,16', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm5', 'collesm5short', '17,18,19,20', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('collesm6', 'collesm6short', '21,22,23,24', 'collesmintro', 3, 'scaletimes5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('howlong', '1', '1', '1', 1, 'howlongoptions');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('othercomments', '1', '1', '1', 0, '');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls20', 'attls20short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls14', 'attls14short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls15', 'attls15short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls16', 'attls16short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls17', 'attls17short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls18', 'attls18short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls19', 'attls19short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls12', 'attls12short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls13', 'attls13short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls11', 'attls11short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls10', 'attls10short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls9', 'attls9short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls8', 'attls8short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls7', 'attls7short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls6', 'attls6short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls5', 'attls5short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls4', 'attls4short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls3', 'attls3short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls1', 'attls1short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attls2', 'attls2short', '1', '1', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm1', 'attlsm1', '45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64', 'attlsmintro', 1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm2', 'attlsm2', '63,62,59,57,55,49,52,50,48,47', 'attlsmintro', -1, 'scaleagree5');
+INSERT INTO prefix_survey_questions (text, shorttext, multi, intro, type, options) VALUES ('attlsm3', 'attlsm3', '46,54,45,51,60,53,56,58,61,64', 'attlsmintro', -1, 'scaleagree5');
+
+rem select * from prefix_survey_questions where text like 'colles%' or text like 'attlsm%'
+
+col id format 99
+select * from prefix_survey_questions;
+
+
+rem
+rem Dumping data for table log_display
+rem
+
+delete from prefix_log_display where module = 'survey';
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'download', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view form', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view graph', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'view report', 'survey', 'name');
+INSERT INTO prefix_log_display (module, action, mtable, field) VALUES ('survey', 'submit', 'survey', 'name');
+select * from prefix_log_display where module = 'survey';
-<?php\r
-\r
-////////////////////////////////////////////////////////////////////////////\r
-/// Blackboard 6.x Format\r
-///\r
-/// This Moodle class provides all functions necessary to import and export\r
-///\r
-///\r
-////////////////////////////////////////////////////////////////////////////\r
-\r
-// Based on default.php, included by ../import.php\r
-\r
-require_once ("$CFG->libdir/xmlize.php");\r
-\r
-class qformat_blackboard_6 extends qformat_default {\r
- function provide_import() {\r
- return true;\r
- }\r
- \r
- \r
- //Function to check and create the needed dir to unzip file to\r
- function check_and_create_import_dir($unique_code) {\r
-\r
- global $CFG; \r
-\r
- $status = $this->check_dir_exists($CFG->dataroot."/temp",true);\r
- if ($status) {\r
- $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);\r
- }\r
- if ($status) {\r
- $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);\r
- }\r
- \r
- return $status;\r
- }\r
- \r
- function clean_temp_dir($dir='') {\r
- // for now we will just say everything happened okay note \r
- // that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import\r
- return true;\r
- \r
- if ($dir == '') {\r
- $dir = $this->temp_dir; \r
- }\r
- $slash = "/";\r
-\r
- // Create arrays to store files and directories\r
- $dir_files = array();\r
- $dir_subdirs = array();\r
-\r
- // Make sure we can delete it\r
- chmod($dir, 0777);\r
-\r
- if ((($handle = opendir($dir))) == FALSE) {\r
- // The directory could not be opened\r
- return false;\r
- }\r
-\r
- // Loop through all directory entries, and construct two temporary arrays containing files and sub directories\r
- while($entry = readdir($handle)) {\r
- if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {\r
- $dir_subdirs[] = $dir. $slash .$entry;\r
- }\r
- else if ($entry != ".." && $entry != ".") {\r
- $dir_files[] = $dir. $slash .$entry;\r
- }\r
- }\r
-\r
- // Delete all files in the curent directory return false and halt if a file cannot be removed\r
- for($i=0; $i<count($dir_files); $i++) {\r
- chmod($dir_files[$i], 0777);\r
- if (((unlink($dir_files[$i]))) == FALSE) {\r
- return false;\r
- }\r
- }\r
-\r
- // Empty sub directories and then remove the directory\r
- for($i=0; $i<count($dir_subdirs); $i++) {\r
- chmod($dir_subdirs[$i], 0777);\r
- if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {\r
- return false;\r
- }\r
- else {\r
- if (rmdir($dir_subdirs[$i]) == FALSE) {\r
- return false;\r
- }\r
- }\r
- }\r
-\r
- // Close directory\r
- closedir($handle);\r
- if (rmdir($this->temp_dir) == FALSE) {\r
- return false; \r
- }\r
- // Success, every thing is gone return true\r
- return true;\r
- }\r
- \r
- //Function to check if a directory exists and, optionally, create it\r
- function check_dir_exists($dir,$create=false) {\r
-\r
- global $CFG; \r
-\r
- $status = true;\r
- if(!is_dir($dir)) {\r
- if (!$create) {\r
- $status = false;\r
- } else {\r
- umask(0000);\r
- $status = mkdir ($dir,$CFG->directorypermissions);\r
- }\r
- }\r
- return $status;\r
- }\r
-\r
- function importpostprocess() {\r
- /// Does any post-processing that may be desired\r
- /// Argument is a simple array of question ids that \r
- /// have just been added.\r
- \r
- // need to clean up temporary directory\r
- return $this->clean_temp_dir();\r
- }\r
-\r
- function copy_file_to_course($filename) {\r
- global $CFG;\r
- global $course;\r
- $filename = str_replace('\\','/',$filename);\r
- $fullpath = $this->temp_dir.'/res00001/'.$filename;\r
- $basename = basename($filename);\r
- \r
- $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';\r
- \r
- if ($this->check_dir_exists($copy_to,true)) {\r
- if(is_readable($fullpath)) {\r
- $copy_to.= '/'.$basename;\r
- if (!copy($fullpath, $copy_to)) {\r
- return false;\r
- }\r
- else {\r
- return $copy_to;\r
- }\r
- }\r
- }\r
- else {\r
- return false; \r
- }\r
- }\r
-\r
- function readdata($filename) {\r
- /// Returns complete file with an array, one item per line\r
- global $CFG;\r
- \r
- $unique_code = time();\r
- $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;\r
- $this->temp_dir = $temp_dir;\r
- if ($this->check_and_create_import_dir($unique_code)) {\r
- if(is_readable($filename)) {\r
- if (!copy($filename, "$temp_dir/bboard.zip")) {\r
- error("Could not copy backup file");\r
- }\r
- if(unzip_file("$temp_dir/bboard.zip", '', false)) {\r
- // assuming that the information is in res0001.dat\r
- // after looking at 6 examples this was always the case\r
- $q_file = "$temp_dir/res00001.dat";\r
- if (is_file($q_file)) {\r
- if (is_readable($q_file)) {\r
- $filearray = file($q_file);\r
- /// Check for Macintosh OS line returns (ie file on one line), and fix\r
- if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {\r
- return explode("\r", $filearray[0]);\r
- } else {\r
- return $filearray;\r
- }\r
- return false; \r
- }\r
- }\r
- else {\r
- error("Could not find question data file in zip"); \r
- }\r
- }\r
- else {\r
- print "filename: $filename<br />tempdir: $temp_dir <br />";\r
- error("Could not unzip file."); \r
- }\r
- }\r
- else {\r
- error ("Could not read uploaded file"); \r
- }\r
- }\r
- else {\r
- error("Could not create temporary directory"); \r
- }\r
- }\r
- \r
- function save_question_options($question) {\r
- return true; \r
- }\r
- \r
- \r
- \r
- function readquestions ($lines) {\r
- /// Parses an array of lines into an array of questions,\r
- /// where each item is a question object as defined by\r
- /// readquestion(). \r
-\r
- $text = implode($lines, " ");\r
- $xml = xmlize($text, 0);\r
-\r
- $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];\r
- $questions = array();\r
-\r
- foreach($raw_questions as $quest) {\r
- $question = $this->create_raw_question($quest);\r
-\r
- switch($question->qtype) {\r
- case "Matching":\r
- $this->process_matching($question, $questions);\r
- break;\r
- case "Multiple Choice":\r
- $this->process_mc($question, $questions);\r
- break;\r
- case "Essay":\r
- $this->process_essay($question, $questions);\r
- break;\r
- case "Multiple Answer":\r
- $this->process_ma($question, $questions);\r
- break;\r
- case "True/False":\r
- $this->process_tf($question, $questions);\r
- break;\r
- case 'Fill in the Blank':\r
- $this->process_fblank($question, $questions);\r
- break;\r
- default:\r
- print "Unknown or unhandled question type: \"$question->qtype\"<br />";\r
- break;\r
- }\r
-\r
- }\r
- return $questions;\r
- }\r
-\r
-\r
-// creates a cleaner object to deal with for processing into moodle\r
-// the object created is NOT a moodle question object\r
-function create_raw_question($quest) {\r
- \r
- $question = $this->defaultquestion();\r
- $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];\r
- $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];\r
-\r
- foreach($presentation->blocks as $pblock) {\r
- \r
- $block = NULL;\r
- $block->type = $pblock['@']['class'];\r
-\r
- switch($block->type) {\r
- case 'QUESTION_BLOCK':\r
- $sub_blocks = $pblock['#']['flow'];\r
- foreach($sub_blocks as $sblock) {\r
- //echo "Calling process_block from line 263<br>";\r
- $this->process_block($sblock, $block); \r
- }\r
- break;\r
-\r
- case 'RESPONSE_BLOCK':\r
- $choices = NULL;\r
- switch($question->qtype) {\r
- case 'Matching':\r
- $bb_subquestions = $pblock['#']['flow'];\r
- $sub_questions = array();\r
- foreach($bb_subquestions as $bb_subquestion) {\r
- $sub_question = NULL;\r
- $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];\r
- $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);\r
- $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
- $choices = array();\r
- $this->process_choices($bb_choices, $choices);\r
- $sub_question->choices = $choices;\r
- if (!isset($block->subquestions)) {\r
- $block->subquestions = array();\r
- }\r
- $block->subquestions[] = $sub_question;\r
- }\r
- break;\r
- case 'Multiple Answer':\r
- $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
- $choices = array();\r
- $this->process_choices($bb_choices, $choices);\r
- $block->choices = $choices;\r
- break;\r
- case 'Essay':\r
- // Doesn't apply since the user responds with text input\r
- break;\r
- case 'Multiple Choice':\r
- $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];\r
- foreach($mc_choices as $mc_choice) {\r
- $choices = NULL;\r
- $choices = $this->process_block($mc_choice, $choices);\r
- $block->choices[] = $choices; \r
- }\r
- break;\r
- case 'Fill in the Blank':\r
- // do nothing?\r
- break;\r
- default:\r
- $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];\r
- $choices = array();\r
- $this->process_choices($bb_choices, $choices);\r
- $block->choices = $choices;\r
- }\r
- break;\r
- case 'RIGHT_MATCH_BLOCK':\r
- $matching_answerset = $pblock['#']['flow'];\r
- $answerset = array();\r
- foreach($matching_answerset as $answer) {\r
- $this->process_block($answer, $bb_answer);\r
- $answerset[] = $bb_answer;\r
- }\r
- $block->matching_answerset = $answerset;\r
- break;\r
- default:\r
- print "UNHANDLED PRESENTATION BLOCK";\r
- break;\r
- }\r
- $question->{$block->type} = $block;\r
- }\r
- \r
- // determine response processing \r
- // there is a section called 'outcomes' that I don't know what to do with\r
- $resprocessing = $quest['#']['resprocessing'];\r
- $respconditions = $resprocessing[0]['#']['respcondition'];\r
- $reponses = array();\r
- if ($question->qtype == 'Matching') {\r
- $this->process_matching_responses($respconditions, $responses);\r
- }\r
- else {\r
- $this->process_responses($respconditions, $responses);\r
- }\r
- $question->responses = $responses;\r
- $feedbackset = $quest['#']['itemfeedback'];\r
- $feedbacks = array();\r
- $this->process_feedback($feedbackset, $feedbacks);\r
- $question->feedback = $feedbacks;\r
- return $question;\r
-}\r
-\r
-function process_block($cur_block, &$block) {\r
- global $course, $CFG;\r
-\r
- $cur_type = $cur_block['@']['class'];\r
- switch($cur_type) {\r
- case 'FORMATTED_TEXT_BLOCK':\r
- $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']); \r
- break;\r
- case 'FILE_BLOCK':\r
- //revisit this to make sure it is working correctly\r
- // Commented out ['matapplication']..., etc. because I \r
- // noticed that when I imported a new Blackboard 6 file\r
- // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06\r
- $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];\r
- if ($block->file != '') {\r
- // if we have a file copy it to the course dir and adjust its name to be visible over the web.\r
- $block->file = $this->copy_file_to_course($block->file);\r
- $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);\r
- }\r
- break;\r
- case 'Block':\r
- if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {\r
- $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];\r
- }\r
- else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {\r
- $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];\r
- }\r
- else if (isset($cur_block['#']['response_label'])) {\r
- // this is a response label block\r
- $sub_blocks = $cur_block['#']['response_label'][0];\r
- if(!isset($block->ident)) {\r
- if(isset($sub_blocks['@']['ident'])) {\r
- $block->ident = $sub_blocks['@']['ident'];\r
- }\r
- }\r
- foreach($sub_blocks['#']['flow_mat'] as $sub_block) {\r
- $this->process_block($sub_block, $block); \r
- }\r
- }\r
- else {\r
- if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {\r
- if (isset($cur_block['#']['flow_mat'])) {\r
- $sub_blocks = $cur_block['#']['flow_mat'];\r
- }\r
- elseif (isset($cur_block['#']['flow'])) {\r
- $sub_blocks = $cur_block['#']['flow'];\r
- }\r
- foreach ($sub_blocks as $sblock) {\r
- // this will recursively grab the sub blocks which should be of one of the other types\r
- $this->process_block($sblock, $block);\r
- }\r
- }\r
- }\r
- break;\r
- case 'LINK_BLOCK':\r
- // not sure how this should be included\r
- if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {\r
- $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];\r
- }\r
- else {\r
- $block->link = '';\r
- }\r
- break; \r
- } \r
- return $block;\r
-}\r
-\r
-function process_choices($bb_choices, &$choices) {\r
- foreach($bb_choices as $choice) {\r
- if (isset($choice['@']['ident'])) {\r
- $cur_choice = $choice['@']['ident'];\r
- }\r
- else { //for multiple answer\r
- $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];\r
- }\r
- if (isset($choice['#']['flow_mat'][0])) { //for multiple answer\r
- $cur_block = $choice['#']['flow_mat'][0];\r
- // Reset $cur_choice to NULL because process_block is expecting an object\r
- // for the second argument and not a string, which is what is was set as\r
- // originally - CT 8/7/06\r
- $cur_choice = null; \r
- $this->process_block($cur_block, $cur_choice);\r
- }\r
- elseif (isset($choice['#']['response_label'])) {\r
- // Reset $cur_choice to NULL because process_block is expecting an object\r
- // for the second argument and not a string, which is what is was set as\r
- // originally - CT 8/7/06\r
- $cur_choice = null; \r
- $this->process_block($choice, $cur_choice);\r
- }\r
- $choices[] = $cur_choice;\r
- } \r
-}\r
-\r
-function process_matching_responses($bb_responses, &$responses) {\r
- foreach($bb_responses as $bb_response) {\r
- $response = NULL;\r
- if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {\r
- $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];\r
- $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];\r
- }\r
- else {\r
- $response->correct = 'Broken Question?';\r
- $response->ident = 'Broken Question?';\r
- }\r
- $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
- $responses[] = $response;\r
- }\r
-}\r
-\r
-function process_responses($bb_responses, &$responses) {\r
- foreach($bb_responses as $bb_response) {\r
- //Added this line to instantiate $response.\r
- // Without instantiating the $response variable, the same object\r
- // gets added to the array\r
- $response = null;\r
- if (isset($bb_response['@']['title'])) {\r
- $response->title = $bb_response['@']['title']; \r
- }\r
- else {\r
- $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];\r
- }\r
- $reponse->ident = array();\r
- if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {\r
- $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#']; \r
- }\r
- else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {\r
- $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#']; \r
- }\r
- \r
- if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {\r
- $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];\r
- foreach($responseset as $rs) {\r
- $response->ident[] = $rs['#'];\r
- if(!isset($response->feedback) and isset( $rs['@'] ) ) {\r
- $response->feedback = $rs['@']['respident'];\r
- } \r
- }\r
- }\r
- else {\r
- $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid']; \r
- }\r
-\r
- // determine what point value to give response\r
- if (isset($bb_response['#']['setvar'])) {\r
- switch ($bb_response['#']['setvar'][0]['#']) {\r
- case "SCORE.max":\r
- $response->fraction = 1;\r
- break;\r
- default:\r
- // I have only seen this being 0 or unset \r
- // there are probably fractional values of SCORE.max, but I'm not sure what they look like\r
- $response->fraction = 0;\r
- break;\r
- }\r
- }\r
- else {\r
- // just going to assume this is the case this is probably not correct.\r
- $response->fraction = 0;\r
- }\r
- \r
- $responses[] = $response;\r
- }\r
-}\r
-\r
-function process_feedback($feedbackset, &$feedbacks) {\r
- foreach($feedbackset as $bb_feedback) {\r
- // Added line $feedback=null so that $feedback does not get reused in the loop\r
- // and added the the $feedbacks[] array multiple times\r
- $feedback = null; \r
- $feedback->ident = $bb_feedback['@']['ident'];\r
- if (isset($bb_feedback['#']['flow_mat'][0])) {\r
- $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);\r
- }\r
- elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {\r
- $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);\r
- }\r
- $feedbacks[] = $feedback;\r
- }\r
-}\r
-\r
-//----------------------------------------\r
-// Process True / False Questions\r
-//----------------------------------------\r
-function process_tf($quest, &$questions) {\r
- $question = $this->defaultquestion();\r
-\r
- $question->qtype = TRUEFALSE;\r
- $question->defaultgrade = 1;\r
- $question->single = 1; // Only one answer is allowed\r
- $question->image = ""; // No images with this format\r
- $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
- // put name in question object\r
- $question->name = $question->questiontext;\r
-\r
- // first choice is true, second is false.\r
- if ($quest->responses[0]->fraction == 1) {\r
- $correct = true; \r
- }\r
- else {\r
- $correct = false; \r
- }\r
- \r
- foreach($quest->feedback as $fb) {\r
- $fback->{$fb->ident} = $fb->text; \r
- }\r
- \r
- if ($correct) { // true is correct\r
- $question->answer = 1;\r
- $question->feedbacktrue = addslashes($fback->correct);\r
- $question->feedbackfalse = addslashes($fback->incorrect);\r
- } else { // false is correct\r
- $question->answer = 0;\r
- $question->feedbacktrue = addslashes($fback->incorrect);\r
- $question->feedbackfalse = addslashes($fback->correct);\r
- }\r
- $questions[] = $question;\r
-}\r
-\r
-\r
-//----------------------------------------\r
-// Process Fill in the Blank\r
-//----------------------------------------\r
-function process_fblank($quest, &$questions) {\r
- $question = $this->defaultquestion();\r
- $question->qtype = SHORTANSWER;\r
- $question->defaultgrade = 1;\r
- $question->single = 1;\r
- $question->usecase = 0;\r
- $question->image = '';\r
- $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
- $question->name = $question->questiontext;\r
- $answers = array();\r
- $fractions = array();\r
- $feedbacks = array();\r
- \r
- // extract the feedback\r
- $feedback = array();\r
- foreach($quest->feedback as $fback) {\r
- if (isset($fback->ident)) {\r
- if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {\r
- $feedback[$fback->ident] = $fback->text;\r
- }\r
- }\r
- }\r
- \r
- foreach($quest->responses as $response) {\r
- if(isset($response->title)) {\r
- if (isset($response->ident[0]['varequal'][0]['#'])) {\r
- //for BB Fill in the Blank, only interested in correct answers\r
- if ($response->feedback = 'correct') {\r
- $answers[] = addslashes($response->ident[0]['varequal'][0]['#']);\r
- $fractions[] = 1;\r
- if (isset($feedback['correct'])) {\r
- $feedbacks[] = addslashes($feedback['correct']);\r
- }\r
- else {\r
- $feedbacks[] = '';\r
- }\r
- }\r
- }\r
- \r
- }\r
- }\r
-\r
- //Adding catchall to so that students can see feedback for incorrect answers when they enter something the \r
- //instructor did not enter\r
- $answers[] = '*';\r
- $fractions[] = 0;\r
- if (isset($feedback['incorrect'])) {\r
- $feedbacks[] = addslashes($feedback['incorrect']);\r
- }\r
- else {\r
- $feedbacks[] = '';\r
- }\r
- \r
- $question->answer = $answers;\r
- $question->fraction = $fractions;\r
- $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of\r
-\r
- if (!empty($question)) {\r
- $questions[] = $question;\r
- }\r
-\r
-}\r
-\r
-//----------------------------------------\r
-// Process Multiple Choice Questions\r
-//----------------------------------------\r
-function process_mc($quest, &$questions) {\r
- $question = $this->defaultquestion();\r
- $question->qtype = MULTICHOICE;\r
- $question->defaultgrade = 1;\r
- $question->single = 1;\r
- $question->image = "";\r
- $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
- $question->name = $question->questiontext;\r
- \r
- $feedback = array();\r
- foreach($quest->feedback as $fback) {\r
- $feedback[$fback->ident] = addslashes($fback->text);\r
- }\r
- \r
- foreach($quest->responses as $response) {\r
- if (isset($response->title)) {\r
- if ($response->title == 'correct') {\r
- // only one answer possible for this qtype so first index is correct answer\r
- $correct = $response->ident[0]['varequal'][0]['#'];\r
- }\r
- }\r
- else {\r
- // fallback method for when the title is not set\r
- if ($response->feedback == 'correct') {\r
- // only one answer possible for this qtype so first index is correct answer\r
- $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06\r
- }\r
- }\r
- }\r
-\r
- $i = 0;\r
- foreach($quest->RESPONSE_BLOCK->choices as $response) {\r
- $question->answer[$i] = addslashes($response->text);\r
- if ($correct == $response->ident) {\r
- $question->fraction[$i] = 1;\r
- // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists\r
- // then specific feedback for this question (maybe this should be switched?, but from my example\r
- // question pools I have not seen response specific feedback, only correct or incorrect feedback\r
- if (!empty($feedback['correct'])) {\r
- $question->feedback[$i] = $feedback['correct'];\r
- }\r
- elseif (!empty($feedback[$i])) {\r
- $question->feedback[$i] = $feedback[$i];\r
- }\r
- else {\r
- // failsafe feedback (should be '' instead?)\r
- $question->feedback[$i] = "correct"; \r
- }\r
- } \r
- else {\r
- $question->fraction[$i] = 0;\r
- if (!empty($feedback['incorrect'])) {\r
- $question->feedback[$i] = $feedback['incorrect'];\r
- }\r
- elseif (!empty($feedback[$i])) {\r
- $question->feedback[$i] = $feedback[$i];\r
- }\r
- else {\r
- // failsafe feedback (should be '' instead?)\r
- $question->feedback[$i] = 'incorrect';\r
- }\r
- }\r
- $i++;\r
- }\r
-\r
- if (!empty($question)) {\r
- $questions[] = $question;\r
- }\r
-}\r
-\r
-//----------------------------------------\r
-// Process Multiple Choice Questions With Multiple Answers\r
-//----------------------------------------\r
-function process_ma($quest, &$questions) {\r
- $question = $this->defaultquestion(); // copied this from process_mc\r
- $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
- $question->name = $question->questiontext; \r
- $question->qtype = MULTICHOICE;\r
- $question->defaultgrade = 1;\r
- $question->single = 0; // More than one answer allowed\r
- $question->image = ""; // No images with this format\r
-\r
- $answers = $quest->responses;\r
- $correct_answers = array();\r
- foreach($answers as $answer) {\r
- if($answer->title == 'correct') {\r
- $answerset = $answer->ident[0]['and'][0]['#']['varequal'];\r
- foreach($answerset as $ans) {\r
- $correct_answers[] = $ans['#'];\r
- }\r
- }\r
- }\r
- \r
- foreach ($quest->feedback as $fb) {\r
- $feedback->{$fb->ident} = addslashes(trim($fb->text));\r
- }\r
- \r
- $correct_answer_count = count($correct_answers);\r
- $choiceset = $quest->RESPONSE_BLOCK->choices;\r
- $i = 0;\r
- foreach($choiceset as $choice) {\r
- $question->answer[$i] = addslashes(trim($choice->text));\r
- if (in_array($choice->ident, $correct_answers)) {\r
- // correct answer\r
- $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places\r
- $question->feedback[$i] = $feedback->correct;\r
- }\r
- else {\r
- // wrong answer \r
- $question->fraction[$i] = 0;\r
- $question->feedback[$i] = $feedback->incorrect;\r
- }\r
- $i++;\r
- }\r
-\r
- $questions[] = $question;\r
-}\r
-\r
-//----------------------------------------\r
-// Process Essay Questions\r
-//----------------------------------------\r
-function process_essay($quest, &$questions) {\r
-// this should be rewritten to accomodate moodle 1.6 essay question type eventually\r
-\r
- if (defined("ESSAY")) {\r
- // treat as short answer\r
- $question = $this->defaultquestion(); // copied this from process_mc\r
- $question->qtype = ESSAY;\r
- $question->defaultgrade = 1;\r
- $question->usecase = 0; // Ignore case\r
- $question->image = ""; // No images with this format\r
- $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));\r
- $question->name = $question->questiontext;\r
- \r
- print $question->name;\r
- \r
- $question->feedback = array();\r
- // not sure where to get the correct answer from\r
- foreach($quest->feedback as $feedback) {\r
- // Added this code to put the possible solution that the\r
- // instructor gives as the Moodle answer for an essay question\r
- if ($feedback->ident == 'solution') {\r
- $question->feedback = $feedback->text;\r
- }\r
- }\r
- //Added because essay/questiontype.php:save_question_option is expecting a \r
- //fraction property - CT 8/10/06\r
- $question->fraction[] = 1; \r
- if (!empty($question)) {\r
- $questions[]=$question;\r
- }\r
- }\r
- else {\r
- print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";\r
- print " Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
- }\r
-}\r
-\r
-//----------------------------------------\r
-// Process Matching Questions\r
-//----------------------------------------\r
-function process_matching($quest, &$questions) {\r
- if (defined("RENDEREDMATCH")) {\r
- $question = $this->defaultquestion($this->defaultquestion());\r
- $question->valid = true;\r
- $question->qtype = RENDEREDMATCH;\r
- $question->defaultgrade = 1;\r
- $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);\r
- $question->name = $question->questiontext;\r
- \r
- foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {\r
- foreach($quest->responses as $rid => $resp) {\r
- if ($resp->ident == $subq->ident) {\r
- $correct = addslashes($resp->correct);\r
- $feedback = addslashes($resp->feedback); \r
- }\r
- }\r
- \r
- foreach($subq->choices as $cid => $choice) {\r
- if ($choice == $correct) {\r
- $question->subquestions[] = addslashes($subq->text);\r
- $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);\r
- }\r
- }\r
- }\r
- \r
- // check format\r
- $status = true;\r
- if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {\r
- $status = false;\r
- }\r
- else {\r
- // need to redo to make sure that no two questions have the same answer (rudimentary now)\r
- foreach($question->subanswers as $qstn) {\r
- if(isset($previous)) {\r
- if ($qstn == $previous) {\r
- $status = false; \r
- } \r
- }\r
- $previous = $qstn;\r
- if ($qstn == '') {\r
- $status = false; \r
- }\r
- }\r
- }\r
- \r
- if ($status) {\r
- $questions[] = $question; \r
- }\r
- else {\r
- global $course, $CFG;\r
- print '<table align="center" border="1">';\r
- print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>'; \r
- \r
- print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;\r
- if (isset($quest->QUESTION_BLOCK->file)) {\r
- print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';\r
- if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {\r
- print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';\r
- }\r
- }\r
- print "</td></tr>";\r
- print "<tr><td>Subquestions:</td><td><ul>";\r
- foreach($quest->responses as $rs) {\r
- $correct_responses->{$rs->ident} = $rs->correct; \r
- }\r
- foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {\r
- print '<li>'.$subq->text.'<ul>';\r
- foreach($subq->choices as $id=>$choice) {\r
- print '<li>';\r
- if ($choice == $correct_responses->{$subq->ident}) {\r
- print '<font color="green">';\r
- }\r
- else {\r
- print '<font color="red">';\r
- }\r
- print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';\r
- }\r
- print '</ul>';\r
- }\r
- print '</ul></td></tr>';\r
- \r
- print '<tr><td>Feedback:</td><td><ul>';\r
- foreach($quest->feedback as $fb) {\r
- print '<li>'.$fb->ident.': '.$fb->text.'</li>';\r
- }\r
- print '</ul></td></tr></table>';\r
- }\r
- }\r
- else {\r
- print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";\r
- print " Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';\r
- }\r
-}\r
-\r
-\r
-function strip_applet_tags_get_mathml($string) {\r
- if(stristr($string, '</APPLET>') === FALSE) {\r
- return $string; \r
- }\r
- else {\r
- // strip all applet tags keeping stuff before/after and inbetween (if mathml) them\r
- while (stristr($string, '</APPLET>') !== FALSE) {\r
- preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);\r
- $string = $mathmls[1].$mathmls[2].$mathmls[3];\r
- }\r
- return $string; \r
- }\r
-}\r
-\r
-} // close object\r
-?>\r
+<?php
+
+////////////////////////////////////////////////////////////////////////////
+/// Blackboard 6.x Format
+///
+/// This Moodle class provides all functions necessary to import and export
+///
+///
+////////////////////////////////////////////////////////////////////////////
+
+// Based on default.php, included by ../import.php
+
+require_once ("$CFG->libdir/xmlize.php");
+
+class qformat_blackboard_6 extends qformat_default {
+ function provide_import() {
+ return true;
+ }
+
+
+ //Function to check and create the needed dir to unzip file to
+ function check_and_create_import_dir($unique_code) {
+
+ global $CFG;
+
+ $status = $this->check_dir_exists($CFG->dataroot."/temp",true);
+ if ($status) {
+ $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import",true);
+ }
+ if ($status) {
+ $status = $this->check_dir_exists($CFG->dataroot."/temp/bbquiz_import/".$unique_code,true);
+ }
+
+ return $status;
+ }
+
+ function clean_temp_dir($dir='') {
+ // for now we will just say everything happened okay note
+ // that a mess may be piling up in $CFG->dataroot/temp/bbquiz_import
+ return true;
+
+ if ($dir == '') {
+ $dir = $this->temp_dir;
+ }
+ $slash = "/";
+
+ // Create arrays to store files and directories
+ $dir_files = array();
+ $dir_subdirs = array();
+
+ // Make sure we can delete it
+ chmod($dir, 0777);
+
+ if ((($handle = opendir($dir))) == FALSE) {
+ // The directory could not be opened
+ return false;
+ }
+
+ // Loop through all directory entries, and construct two temporary arrays containing files and sub directories
+ while($entry = readdir($handle)) {
+ if (is_dir($dir. $slash .$entry) && $entry != ".." && $entry != ".") {
+ $dir_subdirs[] = $dir. $slash .$entry;
+ }
+ else if ($entry != ".." && $entry != ".") {
+ $dir_files[] = $dir. $slash .$entry;
+ }
+ }
+
+ // Delete all files in the curent directory return false and halt if a file cannot be removed
+ for($i=0; $i<count($dir_files); $i++) {
+ chmod($dir_files[$i], 0777);
+ if (((unlink($dir_files[$i]))) == FALSE) {
+ return false;
+ }
+ }
+
+ // Empty sub directories and then remove the directory
+ for($i=0; $i<count($dir_subdirs); $i++) {
+ chmod($dir_subdirs[$i], 0777);
+ if ($this->clean_temp_dir($dir_subdirs[$i]) == FALSE) {
+ return false;
+ }
+ else {
+ if (rmdir($dir_subdirs[$i]) == FALSE) {
+ return false;
+ }
+ }
+ }
+
+ // Close directory
+ closedir($handle);
+ if (rmdir($this->temp_dir) == FALSE) {
+ return false;
+ }
+ // Success, every thing is gone return true
+ return true;
+ }
+
+ //Function to check if a directory exists and, optionally, create it
+ function check_dir_exists($dir,$create=false) {
+
+ global $CFG;
+
+ $status = true;
+ if(!is_dir($dir)) {
+ if (!$create) {
+ $status = false;
+ } else {
+ umask(0000);
+ $status = mkdir ($dir,$CFG->directorypermissions);
+ }
+ }
+ return $status;
+ }
+
+ function importpostprocess() {
+ /// Does any post-processing that may be desired
+ /// Argument is a simple array of question ids that
+ /// have just been added.
+
+ // need to clean up temporary directory
+ return $this->clean_temp_dir();
+ }
+
+ function copy_file_to_course($filename) {
+ global $CFG;
+ global $course;
+ $filename = str_replace('\\','/',$filename);
+ $fullpath = $this->temp_dir.'/res00001/'.$filename;
+ $basename = basename($filename);
+
+ $copy_to = $CFG->dataroot.'/'.$course->id.'/bb_import';
+
+ if ($this->check_dir_exists($copy_to,true)) {
+ if(is_readable($fullpath)) {
+ $copy_to.= '/'.$basename;
+ if (!copy($fullpath, $copy_to)) {
+ return false;
+ }
+ else {
+ return $copy_to;
+ }
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ function readdata($filename) {
+ /// Returns complete file with an array, one item per line
+ global $CFG;
+
+ $unique_code = time();
+ $temp_dir = $CFG->dataroot."/temp/bbquiz_import/".$unique_code;
+ $this->temp_dir = $temp_dir;
+ if ($this->check_and_create_import_dir($unique_code)) {
+ if(is_readable($filename)) {
+ if (!copy($filename, "$temp_dir/bboard.zip")) {
+ error("Could not copy backup file");
+ }
+ if(unzip_file("$temp_dir/bboard.zip", '', false)) {
+ // assuming that the information is in res0001.dat
+ // after looking at 6 examples this was always the case
+ $q_file = "$temp_dir/res00001.dat";
+ if (is_file($q_file)) {
+ if (is_readable($q_file)) {
+ $filearray = file($q_file);
+ /// Check for Macintosh OS line returns (ie file on one line), and fix
+ if (ereg("\r", $filearray[0]) AND !ereg("\n", $filearray[0])) {
+ return explode("\r", $filearray[0]);
+ } else {
+ return $filearray;
+ }
+ return false;
+ }
+ }
+ else {
+ error("Could not find question data file in zip");
+ }
+ }
+ else {
+ print "filename: $filename<br />tempdir: $temp_dir <br />";
+ error("Could not unzip file.");
+ }
+ }
+ else {
+ error ("Could not read uploaded file");
+ }
+ }
+ else {
+ error("Could not create temporary directory");
+ }
+ }
+
+ function save_question_options($question) {
+ return true;
+ }
+
+
+
+ function readquestions ($lines) {
+ /// Parses an array of lines into an array of questions,
+ /// where each item is a question object as defined by
+ /// readquestion().
+
+ $text = implode($lines, " ");
+ $xml = xmlize($text, 0);
+
+ $raw_questions = $xml['questestinterop']['#']['assessment'][0]['#']['section'][0]['#']['item'];
+ $questions = array();
+
+ foreach($raw_questions as $quest) {
+ $question = $this->create_raw_question($quest);
+
+ switch($question->qtype) {
+ case "Matching":
+ $this->process_matching($question, $questions);
+ break;
+ case "Multiple Choice":
+ $this->process_mc($question, $questions);
+ break;
+ case "Essay":
+ $this->process_essay($question, $questions);
+ break;
+ case "Multiple Answer":
+ $this->process_ma($question, $questions);
+ break;
+ case "True/False":
+ $this->process_tf($question, $questions);
+ break;
+ case 'Fill in the Blank':
+ $this->process_fblank($question, $questions);
+ break;
+ default:
+ print "Unknown or unhandled question type: \"$question->qtype\"<br />";
+ break;
+ }
+
+ }
+ return $questions;
+ }
+
+
+// creates a cleaner object to deal with for processing into moodle
+// the object created is NOT a moodle question object
+function create_raw_question($quest) {
+
+ $question = $this->defaultquestion();
+ $question->qtype = $quest['#']['itemmetadata'][0]['#']['bbmd_questiontype'][0]['#'];
+ $presentation->blocks = $quest['#']['presentation'][0]['#']['flow'][0]['#']['flow'];
+
+ foreach($presentation->blocks as $pblock) {
+
+ $block = NULL;
+ $block->type = $pblock['@']['class'];
+
+ switch($block->type) {
+ case 'QUESTION_BLOCK':
+ $sub_blocks = $pblock['#']['flow'];
+ foreach($sub_blocks as $sblock) {
+ //echo "Calling process_block from line 263<br>";
+ $this->process_block($sblock, $block);
+ }
+ break;
+
+ case 'RESPONSE_BLOCK':
+ $choices = NULL;
+ switch($question->qtype) {
+ case 'Matching':
+ $bb_subquestions = $pblock['#']['flow'];
+ $sub_questions = array();
+ foreach($bb_subquestions as $bb_subquestion) {
+ $sub_question = NULL;
+ $sub_question->ident = $bb_subquestion['#']['response_lid'][0]['@']['ident'];
+ $this->process_block($bb_subquestion['#']['flow'][0], $sub_question);
+ $bb_choices = $bb_subquestion['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
+ $choices = array();
+ $this->process_choices($bb_choices, $choices);
+ $sub_question->choices = $choices;
+ if (!isset($block->subquestions)) {
+ $block->subquestions = array();
+ }
+ $block->subquestions[] = $sub_question;
+ }
+ break;
+ case 'Multiple Answer':
+ $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
+ $choices = array();
+ $this->process_choices($bb_choices, $choices);
+ $block->choices = $choices;
+ break;
+ case 'Essay':
+ // Doesn't apply since the user responds with text input
+ break;
+ case 'Multiple Choice':
+ $mc_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'];
+ foreach($mc_choices as $mc_choice) {
+ $choices = NULL;
+ $choices = $this->process_block($mc_choice, $choices);
+ $block->choices[] = $choices;
+ }
+ break;
+ case 'Fill in the Blank':
+ // do nothing?
+ break;
+ default:
+ $bb_choices = $pblock['#']['response_lid'][0]['#']['render_choice'][0]['#']['flow_label'][0]['#']['response_label'];
+ $choices = array();
+ $this->process_choices($bb_choices, $choices);
+ $block->choices = $choices;
+ }
+ break;
+ case 'RIGHT_MATCH_BLOCK':
+ $matching_answerset = $pblock['#']['flow'];
+ $answerset = array();
+ foreach($matching_answerset as $answer) {
+ $this->process_block($answer, $bb_answer);
+ $answerset[] = $bb_answer;
+ }
+ $block->matching_answerset = $answerset;
+ break;
+ default:
+ print "UNHANDLED PRESENTATION BLOCK";
+ break;
+ }
+ $question->{$block->type} = $block;
+ }
+
+ // determine response processing
+ // there is a section called 'outcomes' that I don't know what to do with
+ $resprocessing = $quest['#']['resprocessing'];
+ $respconditions = $resprocessing[0]['#']['respcondition'];
+ $reponses = array();
+ if ($question->qtype == 'Matching') {
+ $this->process_matching_responses($respconditions, $responses);
+ }
+ else {
+ $this->process_responses($respconditions, $responses);
+ }
+ $question->responses = $responses;
+ $feedbackset = $quest['#']['itemfeedback'];
+ $feedbacks = array();
+ $this->process_feedback($feedbackset, $feedbacks);
+ $question->feedback = $feedbacks;
+ return $question;
+}
+
+function process_block($cur_block, &$block) {
+ global $course, $CFG;
+
+ $cur_type = $cur_block['@']['class'];
+ switch($cur_type) {
+ case 'FORMATTED_TEXT_BLOCK':
+ $block->text = $this->strip_applet_tags_get_mathml($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#']);
+ break;
+ case 'FILE_BLOCK':
+ //revisit this to make sure it is working correctly
+ // Commented out ['matapplication']..., etc. because I
+ // noticed that when I imported a new Blackboard 6 file
+ // and printed out the block, the tree did not extend past ['material'][0]['#'] - CT 8/3/06
+ $block->file = $cur_block['#']['material'][0]['#'];//['matapplication'][0]['@']['uri'];
+ if ($block->file != '') {
+ // if we have a file copy it to the course dir and adjust its name to be visible over the web.
+ $block->file = $this->copy_file_to_course($block->file);
+ $block->file = $CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($block->file);
+ }
+ break;
+ case 'Block':
+ if (isset($cur_block['#']['material'][0]['#']['mattext'][0]['#'])) {
+ $block->text = $cur_block['#']['material'][0]['#']['mattext'][0]['#'];
+ }
+ else if (isset($cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'])) {
+ $block->text = $cur_block['#']['material'][0]['#']['mat_extension'][0]['#']['mat_formattedtext'][0]['#'];
+ }
+ else if (isset($cur_block['#']['response_label'])) {
+ // this is a response label block
+ $sub_blocks = $cur_block['#']['response_label'][0];
+ if(!isset($block->ident)) {
+ if(isset($sub_blocks['@']['ident'])) {
+ $block->ident = $sub_blocks['@']['ident'];
+ }
+ }
+ foreach($sub_blocks['#']['flow_mat'] as $sub_block) {
+ $this->process_block($sub_block, $block);
+ }
+ }
+ else {
+ if (isset($cur_block['#']['flow_mat']) || isset($cur_block['#']['flow'])) {
+ if (isset($cur_block['#']['flow_mat'])) {
+ $sub_blocks = $cur_block['#']['flow_mat'];
+ }
+ elseif (isset($cur_block['#']['flow'])) {
+ $sub_blocks = $cur_block['#']['flow'];
+ }
+ foreach ($sub_blocks as $sblock) {
+ // this will recursively grab the sub blocks which should be of one of the other types
+ $this->process_block($sblock, $block);
+ }
+ }
+ }
+ break;
+ case 'LINK_BLOCK':
+ // not sure how this should be included
+ if (!empty($cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'])) {
+ $block->link = $cur_block['#']['material'][0]['#']['mattext'][0]['@']['uri'];
+ }
+ else {
+ $block->link = '';
+ }
+ break;
+ }
+ return $block;
+}
+
+function process_choices($bb_choices, &$choices) {
+ foreach($bb_choices as $choice) {
+ if (isset($choice['@']['ident'])) {
+ $cur_choice = $choice['@']['ident'];
+ }
+ else { //for multiple answer
+ $cur_choice = $choice['#']['response_label'][0];//['@']['ident'];
+ }
+ if (isset($choice['#']['flow_mat'][0])) { //for multiple answer
+ $cur_block = $choice['#']['flow_mat'][0];
+ // Reset $cur_choice to NULL because process_block is expecting an object
+ // for the second argument and not a string, which is what is was set as
+ // originally - CT 8/7/06
+ $cur_choice = null;
+ $this->process_block($cur_block, $cur_choice);
+ }
+ elseif (isset($choice['#']['response_label'])) {
+ // Reset $cur_choice to NULL because process_block is expecting an object
+ // for the second argument and not a string, which is what is was set as
+ // originally - CT 8/7/06
+ $cur_choice = null;
+ $this->process_block($choice, $cur_choice);
+ }
+ $choices[] = $cur_choice;
+ }
+}
+
+function process_matching_responses($bb_responses, &$responses) {
+ foreach($bb_responses as $bb_response) {
+ $response = NULL;
+ if (isset($bb_response['#']['conditionvar'][0]['#']['varequal'])) {
+ $response->correct = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['#'];
+ $response->ident = $bb_response['#']['conditionvar'][0]['#']['varequal'][0]['@']['respident'];
+ }
+ else {
+ $response->correct = 'Broken Question?';
+ $response->ident = 'Broken Question?';
+ }
+ $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
+ $responses[] = $response;
+ }
+}
+
+function process_responses($bb_responses, &$responses) {
+ foreach($bb_responses as $bb_response) {
+ //Added this line to instantiate $response.
+ // Without instantiating the $response variable, the same object
+ // gets added to the array
+ $response = null;
+ if (isset($bb_response['@']['title'])) {
+ $response->title = $bb_response['@']['title'];
+ }
+ else {
+ $reponse->title = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
+ }
+ $reponse->ident = array();
+ if (isset($bb_response['#']['conditionvar'][0]['#'])){//['varequal'][0]['#'])) {
+ $response->ident[0] = $bb_response['#']['conditionvar'][0]['#'];//['varequal'][0]['#'];
+ }
+ else if (isset($bb_response['#']['conditionvar'][0]['#']['other'][0]['#'])) {
+ $response->ident[0] = $bb_response['#']['conditionvar'][0]['#']['other'][0]['#'];
+ }
+
+ if (isset($bb_response['#']['conditionvar'][0]['#']['and'])){//[0]['#'])) {
+ $responseset = $bb_response['#']['conditionvar'][0]['#']['and'];//[0]['#']['varequal'];
+ foreach($responseset as $rs) {
+ $response->ident[] = $rs['#'];
+ if(!isset($response->feedback) and isset( $rs['@'] ) ) {
+ $response->feedback = $rs['@']['respident'];
+ }
+ }
+ }
+ else {
+ $response->feedback = $bb_response['#']['displayfeedback'][0]['@']['linkrefid'];
+ }
+
+ // determine what point value to give response
+ if (isset($bb_response['#']['setvar'])) {
+ switch ($bb_response['#']['setvar'][0]['#']) {
+ case "SCORE.max":
+ $response->fraction = 1;
+ break;
+ default:
+ // I have only seen this being 0 or unset
+ // there are probably fractional values of SCORE.max, but I'm not sure what they look like
+ $response->fraction = 0;
+ break;
+ }
+ }
+ else {
+ // just going to assume this is the case this is probably not correct.
+ $response->fraction = 0;
+ }
+
+ $responses[] = $response;
+ }
+}
+
+function process_feedback($feedbackset, &$feedbacks) {
+ foreach($feedbackset as $bb_feedback) {
+ // Added line $feedback=null so that $feedback does not get reused in the loop
+ // and added the the $feedbacks[] array multiple times
+ $feedback = null;
+ $feedback->ident = $bb_feedback['@']['ident'];
+ if (isset($bb_feedback['#']['flow_mat'][0])) {
+ $this->process_block($bb_feedback['#']['flow_mat'][0], $feedback);
+ }
+ elseif (isset($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0])) {
+ $this->process_block($bb_feedback['#']['solution'][0]['#']['solutionmaterial'][0]['#']['flow_mat'][0], $feedback);
+ }
+ $feedbacks[] = $feedback;
+ }
+}
+
+//----------------------------------------
+// Process True / False Questions
+//----------------------------------------
+function process_tf($quest, &$questions) {
+ $question = $this->defaultquestion();
+
+ $question->qtype = TRUEFALSE;
+ $question->defaultgrade = 1;
+ $question->single = 1; // Only one answer is allowed
+ $question->image = ""; // No images with this format
+ $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+ // put name in question object
+ $question->name = $question->questiontext;
+
+ // first choice is true, second is false.
+ if ($quest->responses[0]->fraction == 1) {
+ $correct = true;
+ }
+ else {
+ $correct = false;
+ }
+
+ foreach($quest->feedback as $fb) {
+ $fback->{$fb->ident} = $fb->text;
+ }
+
+ if ($correct) { // true is correct
+ $question->answer = 1;
+ $question->feedbacktrue = addslashes($fback->correct);
+ $question->feedbackfalse = addslashes($fback->incorrect);
+ } else { // false is correct
+ $question->answer = 0;
+ $question->feedbacktrue = addslashes($fback->incorrect);
+ $question->feedbackfalse = addslashes($fback->correct);
+ }
+ $questions[] = $question;
+}
+
+
+//----------------------------------------
+// Process Fill in the Blank
+//----------------------------------------
+function process_fblank($quest, &$questions) {
+ $question = $this->defaultquestion();
+ $question->qtype = SHORTANSWER;
+ $question->defaultgrade = 1;
+ $question->single = 1;
+ $question->usecase = 0;
+ $question->image = '';
+ $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+ $question->name = $question->questiontext;
+ $answers = array();
+ $fractions = array();
+ $feedbacks = array();
+
+ // extract the feedback
+ $feedback = array();
+ foreach($quest->feedback as $fback) {
+ if (isset($fback->ident)) {
+ if ($fback->ident == 'correct' || $fback->ident == 'incorrect') {
+ $feedback[$fback->ident] = $fback->text;
+ }
+ }
+ }
+
+ foreach($quest->responses as $response) {
+ if(isset($response->title)) {
+ if (isset($response->ident[0]['varequal'][0]['#'])) {
+ //for BB Fill in the Blank, only interested in correct answers
+ if ($response->feedback = 'correct') {
+ $answers[] = addslashes($response->ident[0]['varequal'][0]['#']);
+ $fractions[] = 1;
+ if (isset($feedback['correct'])) {
+ $feedbacks[] = addslashes($feedback['correct']);
+ }
+ else {
+ $feedbacks[] = '';
+ }
+ }
+ }
+
+ }
+ }
+
+ //Adding catchall to so that students can see feedback for incorrect answers when they enter something the
+ //instructor did not enter
+ $answers[] = '*';
+ $fractions[] = 0;
+ if (isset($feedback['incorrect'])) {
+ $feedbacks[] = addslashes($feedback['incorrect']);
+ }
+ else {
+ $feedbacks[] = '';
+ }
+
+ $question->answer = $answers;
+ $question->fraction = $fractions;
+ $question->feedback = $feedbacks; // Changed to assign $feedbacks to $question->feedback instead of
+
+ if (!empty($question)) {
+ $questions[] = $question;
+ }
+
+}
+
+//----------------------------------------
+// Process Multiple Choice Questions
+//----------------------------------------
+function process_mc($quest, &$questions) {
+ $question = $this->defaultquestion();
+ $question->qtype = MULTICHOICE;
+ $question->defaultgrade = 1;
+ $question->single = 1;
+ $question->image = "";
+ $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+ $question->name = $question->questiontext;
+
+ $feedback = array();
+ foreach($quest->feedback as $fback) {
+ $feedback[$fback->ident] = addslashes($fback->text);
+ }
+
+ foreach($quest->responses as $response) {
+ if (isset($response->title)) {
+ if ($response->title == 'correct') {
+ // only one answer possible for this qtype so first index is correct answer
+ $correct = $response->ident[0]['varequal'][0]['#'];
+ }
+ }
+ else {
+ // fallback method for when the title is not set
+ if ($response->feedback == 'correct') {
+ // only one answer possible for this qtype so first index is correct answer
+ $correct = $response->ident[0]['varequal'][0]['#']; // added [0]['varequal'][0]['#'] to $response->ident - CT 8/9/06
+ }
+ }
+ }
+
+ $i = 0;
+ foreach($quest->RESPONSE_BLOCK->choices as $response) {
+ $question->answer[$i] = addslashes($response->text);
+ if ($correct == $response->ident) {
+ $question->fraction[$i] = 1;
+ // this is a bit of a hack to catch the feedback... first we see if a 'correct' feedback exists
+ // then specific feedback for this question (maybe this should be switched?, but from my example
+ // question pools I have not seen response specific feedback, only correct or incorrect feedback
+ if (!empty($feedback['correct'])) {
+ $question->feedback[$i] = $feedback['correct'];
+ }
+ elseif (!empty($feedback[$i])) {
+ $question->feedback[$i] = $feedback[$i];
+ }
+ else {
+ // failsafe feedback (should be '' instead?)
+ $question->feedback[$i] = "correct";
+ }
+ }
+ else {
+ $question->fraction[$i] = 0;
+ if (!empty($feedback['incorrect'])) {
+ $question->feedback[$i] = $feedback['incorrect'];
+ }
+ elseif (!empty($feedback[$i])) {
+ $question->feedback[$i] = $feedback[$i];
+ }
+ else {
+ // failsafe feedback (should be '' instead?)
+ $question->feedback[$i] = 'incorrect';
+ }
+ }
+ $i++;
+ }
+
+ if (!empty($question)) {
+ $questions[] = $question;
+ }
+}
+
+//----------------------------------------
+// Process Multiple Choice Questions With Multiple Answers
+//----------------------------------------
+function process_ma($quest, &$questions) {
+ $question = $this->defaultquestion(); // copied this from process_mc
+ $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+ $question->name = $question->questiontext;
+ $question->qtype = MULTICHOICE;
+ $question->defaultgrade = 1;
+ $question->single = 0; // More than one answer allowed
+ $question->image = ""; // No images with this format
+
+ $answers = $quest->responses;
+ $correct_answers = array();
+ foreach($answers as $answer) {
+ if($answer->title == 'correct') {
+ $answerset = $answer->ident[0]['and'][0]['#']['varequal'];
+ foreach($answerset as $ans) {
+ $correct_answers[] = $ans['#'];
+ }
+ }
+ }
+
+ foreach ($quest->feedback as $fb) {
+ $feedback->{$fb->ident} = addslashes(trim($fb->text));
+ }
+
+ $correct_answer_count = count($correct_answers);
+ $choiceset = $quest->RESPONSE_BLOCK->choices;
+ $i = 0;
+ foreach($choiceset as $choice) {
+ $question->answer[$i] = addslashes(trim($choice->text));
+ if (in_array($choice->ident, $correct_answers)) {
+ // correct answer
+ $question->fraction[$i] = floor(100000/$correct_answer_count)/100000; // strange behavior if we have more than 5 decimal places
+ $question->feedback[$i] = $feedback->correct;
+ }
+ else {
+ // wrong answer
+ $question->fraction[$i] = 0;
+ $question->feedback[$i] = $feedback->incorrect;
+ }
+ $i++;
+ }
+
+ $questions[] = $question;
+}
+
+//----------------------------------------
+// Process Essay Questions
+//----------------------------------------
+function process_essay($quest, &$questions) {
+// this should be rewritten to accomodate moodle 1.6 essay question type eventually
+
+ if (defined("ESSAY")) {
+ // treat as short answer
+ $question = $this->defaultquestion(); // copied this from process_mc
+ $question->qtype = ESSAY;
+ $question->defaultgrade = 1;
+ $question->usecase = 0; // Ignore case
+ $question->image = ""; // No images with this format
+ $question->questiontext = addslashes(trim($quest->QUESTION_BLOCK->text));
+ $question->name = $question->questiontext;
+
+ print $question->name;
+
+ $question->feedback = array();
+ // not sure where to get the correct answer from
+ foreach($quest->feedback as $feedback) {
+ // Added this code to put the possible solution that the
+ // instructor gives as the Moodle answer for an essay question
+ if ($feedback->ident == 'solution') {
+ $question->feedback = $feedback->text;
+ }
+ }
+ //Added because essay/questiontype.php:save_question_option is expecting a
+ //fraction property - CT 8/10/06
+ $question->fraction[] = 1;
+ if (!empty($question)) {
+ $questions[]=$question;
+ }
+ }
+ else {
+ print "Essay question types are not handled because the quiz question type 'Essay' does not exist in this installation of Moodle<br/>";
+ print " Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
+ }
+}
+
+//----------------------------------------
+// Process Matching Questions
+//----------------------------------------
+function process_matching($quest, &$questions) {
+ if (defined("RENDEREDMATCH")) {
+ $question = $this->defaultquestion($this->defaultquestion());
+ $question->valid = true;
+ $question->qtype = RENDEREDMATCH;
+ $question->defaultgrade = 1;
+ $question->questiontext = addslashes($quest->QUESTION_BLOCK->text);
+ $question->name = $question->questiontext;
+
+ foreach($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
+ foreach($quest->responses as $rid => $resp) {
+ if ($resp->ident == $subq->ident) {
+ $correct = addslashes($resp->correct);
+ $feedback = addslashes($resp->feedback);
+ }
+ }
+
+ foreach($subq->choices as $cid => $choice) {
+ if ($choice == $correct) {
+ $question->subquestions[] = addslashes($subq->text);
+ $question->subanswers[] = addslashes($quest->RIGHT_MATCH_BLOCK->matching_answerset[$cid]->text);
+ }
+ }
+ }
+
+ // check format
+ $status = true;
+ if ( count($quest->RESPONSE_BLOCK->subquestions) > count($quest->RIGHT_MATCH_BLOCK->matching_answerset) || count($question->subquestions) < 2) {
+ $status = false;
+ }
+ else {
+ // need to redo to make sure that no two questions have the same answer (rudimentary now)
+ foreach($question->subanswers as $qstn) {
+ if(isset($previous)) {
+ if ($qstn == $previous) {
+ $status = false;
+ }
+ }
+ $previous = $qstn;
+ if ($qstn == '') {
+ $status = false;
+ }
+ }
+ }
+
+ if ($status) {
+ $questions[] = $question;
+ }
+ else {
+ global $course, $CFG;
+ print '<table align="center" border="1">';
+ print '<tr><td colspan="2" style="background-color:#FF8888;">This matching question is malformed. Please ensure there are no blank answers, no two questions have the same answer, and/or there are correct answers for each question. There must be at least as many subanswers as subquestions, and at least one subquestion.</td></tr>';
+
+ print "<tr><td>Question:</td><td>".$quest->QUESTION_BLOCK->text;
+ if (isset($quest->QUESTION_BLOCK->file)) {
+ print '<br/><font color="red">There is a subfile contained in the zipfile that has been copied to course files: bb_import/'.basename($quest->QUESTION_BLOCK->file).'</font>';
+ if (preg_match('/(gif|jpg|jpeg|png)$/i', $quest->QUESTION_BLOCK->file)) {
+ print '<img src="'.$CFG->wwwroot.'/file.php/'.$course->id.'/bb_import/'.basename($quest->QUESTION_BLOCK->file).'" />';
+ }
+ }
+ print "</td></tr>";
+ print "<tr><td>Subquestions:</td><td><ul>";
+ foreach($quest->responses as $rs) {
+ $correct_responses->{$rs->ident} = $rs->correct;
+ }
+ foreach($quest->RESPONSE_BLOCK->subquestions as $subq) {
+ print '<li>'.$subq->text.'<ul>';
+ foreach($subq->choices as $id=>$choice) {
+ print '<li>';
+ if ($choice == $correct_responses->{$subq->ident}) {
+ print '<font color="green">';
+ }
+ else {
+ print '<font color="red">';
+ }
+ print $quest->RIGHT_MATCH_BLOCK->matching_answerset[$id]->text.'</font></li>';
+ }
+ print '</ul>';
+ }
+ print '</ul></td></tr>';
+
+ print '<tr><td>Feedback:</td><td><ul>';
+ foreach($quest->feedback as $fb) {
+ print '<li>'.$fb->ident.': '.$fb->text.'</li>';
+ }
+ print '</ul></td></tr></table>';
+ }
+ }
+ else {
+ print "Matching question types are not handled because the quiz question type 'Rendered Matching' does not exist in this installation of Moodle<br/>";
+ print " Omitted Question: ".$quest->QUESTION_BLOCK->text.'<br/><br/>';
+ }
+}
+
+
+function strip_applet_tags_get_mathml($string) {
+ if(stristr($string, '</APPLET>') === FALSE) {
+ return $string;
+ }
+ else {
+ // strip all applet tags keeping stuff before/after and inbetween (if mathml) them
+ while (stristr($string, '</APPLET>') !== FALSE) {
+ preg_match("/(.*)\<applet.*value=\"(\<math\>.*\<\/math\>)\".*\<\/applet\>(.*)/i",$string, $mathmls);
+ $string = $mathmls[1].$mathmls[2].$mathmls[3];
+ }
+ return $string;
+ }
+}
+
+} // close object
+?>
-<?xml version="1.0" ?>\r
-<activityset setno="2">\r
- <title>Maths</title>\r
- <questions>\r
- <question type="multiChoice">\r
- <text>The ages, in years, of 10 horses in a field were 3, 3, 4, 5, 7, 7, 7, 8, 8, 8,<p>\r
-Which one of the following is true?</text>\r
- <award>1</award>\r
- <hint>mean = (3+3+4+5+7+7+7+8+8+8)/10 = 6<p>\r
-median = 7 i.e the middle number<p>\r
-range = 8-3 = 5</hint>\r
- <answer>\r
- <option correct="yes">median > mean > range</option>\r
- <option correct="no">mean = median</option>\r
- <option correct="no">mean > median > range</option>\r
- <option correct="no">median > range > mean</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>At a college, students are given a points score calculated from their GCSE grades.<p>\r
-Someone with 4 A grades and 4 B grades gains a score of 36 points.<br>Someone with 2 A grades and 4 B grades gains a score of 26 points.<br>Someone with 3 A grades and 3 B grades would have a score of</text>\r
- <award>1</award>\r
- <hint>4A + 4B = 36 and 2A + 4B = 26<p>solving simultaneously gives A = 5 and B = 4</hint>\r
- <answer>\r
- <option correct="yes">27 points</option>\r
- <option correct="no">21 points</option>\r
- <option correct="no">30 points</option>\r
- <option correct="no">31 points</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>A sequence consists of adding the previous three terms together to form the next term. The first three terms of the sequence are 1, 2, 3.<p>\r
-What is the sixth term in the sequence?</text>\r
- <award>1</award>\r
- <hint>1, 2, 3, 6, 11, ...</hint>\r
- <answer>\r
- <option correct="yes">20</option>\r
- <option correct="no">6</option>\r
- <option correct="no">11</option>\r
- <option correct="no">13</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>The value of an item is described as decreasing exponentially. Which description below best matches this statement?</text>\r
- <award>1</award>\r
- <hint>No hint - you either know this or you don't!</hint>\r
- <answer>\r
- <option correct="yes">The value falls by a smaller amount each year.</option>\r
- <option correct="no">The value falls by the same amount each year.</option>\r
- <option correct="no">The value falls by the same amount each year for a while, and then remains constant.</option>\r
- <option correct="no">The value falls by a larger amount each year.</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>Consider the statement<p>\r
-"Schools with high numbers of pupils on free school meals do not do well in league tables."<p>\r
-Which of the following statements follows logically from the one above?</text>\r
- <award>1</award>\r
- <hint>Factors other than the number of pupils on free school meals affect how well a school does in league tables.</hint>\r
- <answer>\r
- <option correct="yes">Schools which do well in league tables do not have high numbers of pupils on free school meals.</option>\r
- <option correct="no">Schools with low numbers of pupils on free school meals do well in league tables.</option>\r
- <option correct="no">Making all pupils pay for school meals will improve league table results.</option>\r
- <option correct="no">Schools which do not do well in league tables have high numbers of pupils on free school meals.</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>The force between two point electric charges is inversely proportional to the square of their distance apart. What effect does doubling this distance have on the force?</text>\r
- <award>1</award>\r
- <hint>Inversely proportional means that increasing the distance decreases the force.<br>2 squared gives 4.</hint>\r
- <answer>\r
- <option correct="yes">The force decreases by a factor of four.</option>\r
- <option correct="no">The force is halved.</option>\r
- <option correct="no">The force is doubled.</option>\r
- <option correct="no">The force increases by a factor of four.</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>Two of the five playing cards that Colin has are aces. He shuffles the five cards, then puts them face down on the table. Madge takes a card and then another. The probability that she now has <b>both</b> of the aces is</text>\r
- <award>1</award>\r
- <hint>2/5 x 1/4</hint>\r
- <answer>\r
- <option correct="yes">1/10</option>\r
- <option correct="no">4/25</option>\r
- <option correct="no">1/5</option>\r
- <option correct="no">2/5</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>A college's guidelines say that classes must have a minimum of 12 students and a maximum of 20 students. For what numbers of students studying a particular subject is it impossible to run classes without breaking the guidelines?</text>\r
- <award>1</award>\r
- <hint>between 12 and 20 students - one class<br>\r
-between 24 and 36 students - two classes<br>\r
-between 36 and 40 students - two classes</hint>\r
- <answer>\r
- <option correct="yes">between 20 and 24 students</option>\r
- <option correct="no">between 12 and 20 students</option>\r
- <option correct="no">between 24 and 36 students</option>\r
- <option correct="no">between 36 and 40 students</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>The ages of two friends are in the ratio 3:4. In 8 years time their ages will be in the ratio 5:6. How old are they now?</text>\r
- <award>1</award>\r
- <hint>(12+8):(16+8) = 20:24 = 5:6</hint>\r
- <answer>\r
- <option correct="yes">12, 16</option>\r
- <option correct="no">3, 4</option>\r
- <option correct="no">6, 8</option>\r
- <option correct="no">9, 12</option>\r
- </answer>\r
- </question>\r
- <question type="multiChoice">\r
- <text>A heavy construction vehicle travels for 40 minutes between sites, at an average speed of 16 km per second. The distance between sites is</text>\r
- <award>1</award>\r
- <hint>16/60 x 40</hint>\r
- <answer>\r
- <option correct="yes">10.7 km</option>\r
- <option correct="no">2.5 km</option>\r
- <option correct="no">6.4 km</option>\r
- <option correct="no">38.4 km</option>\r
- </answer>\r
- </question>\r
- <question type="multianswerchoice">\r
- <text>Which of the following are features of a Virtual Learning Environment? (Select all that apply)</text>\r
- <hint />\r
- <answer>\r
- <option correct="yes" award="1" deduct="0">course resources are available from home and from college</option>\r
- <option correct="yes" award="1" deduct="0">forums enable collaborative work</option>\r
- <option correct="yes" award="1" deduct="0">assessments can give instant feedback</option>\r
- <option correct="yes" award="1" deduct="0">course progress is recorded</option>\r
- <option correct="no" award="1" deduct="0">kettle is put on automatically for tea/coffee</option>\r
- </answer>\r
- </question>\r
- <question type="multianswerchoice">\r
- <text>Which of the following may a Virtual Learning Environment be used for? (Select all that apply)</text>\r
- <hint />\r
- <answer>\r
- <option correct="yes" award="1" deduct="1">delivering a course online</option>\r
- <option correct="yes" award="1" deduct="1">supporting face-to-face teaching</option>\r
- <option correct="no" award="1" deduct="0">as a complete replacement for teachers</option>\r
- </answer>\r
- </question>\r
- </questions>\r
-</activityset>\r
+<?xml version="1.0" ?>
+<activityset setno="2">
+ <title>Maths</title>
+ <questions>
+ <question type="multiChoice">
+ <text>The ages, in years, of 10 horses in a field were 3, 3, 4, 5, 7, 7, 7, 8, 8, 8,<p>
+Which one of the following is true?</text>
+ <award>1</award>
+ <hint>mean = (3+3+4+5+7+7+7+8+8+8)/10 = 6<p>
+median = 7 i.e the middle number<p>
+range = 8-3 = 5</hint>
+ <answer>
+ <option correct="yes">median > mean > range</option>
+ <option correct="no">mean = median</option>
+ <option correct="no">mean > median > range</option>
+ <option correct="no">median > range > mean</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>At a college, students are given a points score calculated from their GCSE grades.<p>
+Someone with 4 A grades and 4 B grades gains a score of 36 points.<br>Someone with 2 A grades and 4 B grades gains a score of 26 points.<br>Someone with 3 A grades and 3 B grades would have a score of</text>
+ <award>1</award>
+ <hint>4A + 4B = 36 and 2A + 4B = 26<p>solving simultaneously gives A = 5 and B = 4</hint>
+ <answer>
+ <option correct="yes">27 points</option>
+ <option correct="no">21 points</option>
+ <option correct="no">30 points</option>
+ <option correct="no">31 points</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>A sequence consists of adding the previous three terms together to form the next term. The first three terms of the sequence are 1, 2, 3.<p>
+What is the sixth term in the sequence?</text>
+ <award>1</award>
+ <hint>1, 2, 3, 6, 11, ...</hint>
+ <answer>
+ <option correct="yes">20</option>
+ <option correct="no">6</option>
+ <option correct="no">11</option>
+ <option correct="no">13</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>The value of an item is described as decreasing exponentially. Which description below best matches this statement?</text>
+ <award>1</award>
+ <hint>No hint - you either know this or you don't!</hint>
+ <answer>
+ <option correct="yes">The value falls by a smaller amount each year.</option>
+ <option correct="no">The value falls by the same amount each year.</option>
+ <option correct="no">The value falls by the same amount each year for a while, and then remains constant.</option>
+ <option correct="no">The value falls by a larger amount each year.</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>Consider the statement<p>
+"Schools with high numbers of pupils on free school meals do not do well in league tables."<p>
+Which of the following statements follows logically from the one above?</text>
+ <award>1</award>
+ <hint>Factors other than the number of pupils on free school meals affect how well a school does in league tables.</hint>
+ <answer>
+ <option correct="yes">Schools which do well in league tables do not have high numbers of pupils on free school meals.</option>
+ <option correct="no">Schools with low numbers of pupils on free school meals do well in league tables.</option>
+ <option correct="no">Making all pupils pay for school meals will improve league table results.</option>
+ <option correct="no">Schools which do not do well in league tables have high numbers of pupils on free school meals.</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>The force between two point electric charges is inversely proportional to the square of their distance apart. What effect does doubling this distance have on the force?</text>
+ <award>1</award>
+ <hint>Inversely proportional means that increasing the distance decreases the force.<br>2 squared gives 4.</hint>
+ <answer>
+ <option correct="yes">The force decreases by a factor of four.</option>
+ <option correct="no">The force is halved.</option>
+ <option correct="no">The force is doubled.</option>
+ <option correct="no">The force increases by a factor of four.</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>Two of the five playing cards that Colin has are aces. He shuffles the five cards, then puts them face down on the table. Madge takes a card and then another. The probability that she now has <b>both</b> of the aces is</text>
+ <award>1</award>
+ <hint>2/5 x 1/4</hint>
+ <answer>
+ <option correct="yes">1/10</option>
+ <option correct="no">4/25</option>
+ <option correct="no">1/5</option>
+ <option correct="no">2/5</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>A college's guidelines say that classes must have a minimum of 12 students and a maximum of 20 students. For what numbers of students studying a particular subject is it impossible to run classes without breaking the guidelines?</text>
+ <award>1</award>
+ <hint>between 12 and 20 students - one class<br>
+between 24 and 36 students - two classes<br>
+between 36 and 40 students - two classes</hint>
+ <answer>
+ <option correct="yes">between 20 and 24 students</option>
+ <option correct="no">between 12 and 20 students</option>
+ <option correct="no">between 24 and 36 students</option>
+ <option correct="no">between 36 and 40 students</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>The ages of two friends are in the ratio 3:4. In 8 years time their ages will be in the ratio 5:6. How old are they now?</text>
+ <award>1</award>
+ <hint>(12+8):(16+8) = 20:24 = 5:6</hint>
+ <answer>
+ <option correct="yes">12, 16</option>
+ <option correct="no">3, 4</option>
+ <option correct="no">6, 8</option>
+ <option correct="no">9, 12</option>
+ </answer>
+ </question>
+ <question type="multiChoice">
+ <text>A heavy construction vehicle travels for 40 minutes between sites, at an average speed of 16 km per second. The distance between sites is</text>
+ <award>1</award>
+ <hint>16/60 x 40</hint>
+ <answer>
+ <option correct="yes">10.7 km</option>
+ <option correct="no">2.5 km</option>
+ <option correct="no">6.4 km</option>
+ <option correct="no">38.4 km</option>
+ </answer>
+ </question>
+ <question type="multianswerchoice">
+ <text>Which of the following are features of a Virtual Learning Environment? (Select all that apply)</text>
+ <hint />
+ <answer>
+ <option correct="yes" award="1" deduct="0">course resources are available from home and from college</option>
+ <option correct="yes" award="1" deduct="0">forums enable collaborative work</option>
+ <option correct="yes" award="1" deduct="0">assessments can give instant feedback</option>
+ <option correct="yes" award="1" deduct="0">course progress is recorded</option>
+ <option correct="no" award="1" deduct="0">kettle is put on automatically for tea/coffee</option>
+ </answer>
+ </question>
+ <question type="multianswerchoice">
+ <text>Which of the following may a Virtual Learning Environment be used for? (Select all that apply)</text>
+ <hint />
+ <answer>
+ <option correct="yes" award="1" deduct="1">delivering a course online</option>
+ <option correct="yes" award="1" deduct="1">supporting face-to-face teaching</option>
+ <option correct="no" award="1" deduct="0">as a complete replacement for teachers</option>
+ </answer>
+ </question>
+ </questions>
+</activityset>
-- Ajouter un espace après un symbole <= s'il préfixe une parenthèse ouvrante.\r
-- Gérer 'and', 'or', ... comme &&, ||\r
-- Ne pas mettre de '$' sur les @param si aucun nom de variable n'esp spécifié.\r
-- Ajouter OneTrueBrace pour les if, while, for, else ... (Gustavo Carreno <gcarreno@netvisao.pt>, Richard Bateman <richard@randyb.byu.edu>, Yaroslav Shvetsov <yaro@totaldesign.ru>, Chris Small <chris@owta.net>)\r
-- Remove blank lines (Sergio Marchesini <smarques@tin.it>)\r
-- Forcer une ligne vide après une déclaration de fonction (Richard Bateman <richard@randyb.byu.edu>)\r
-\r
+- Ajouter un espace apr�s un symbole <= s'il pr�fixe une parenth�se ouvrante.
+- G�rer 'and', 'or', ... comme &&, ||
+- Ne pas mettre de '$' sur les @param si aucun nom de variable n'esp sp�cifi�.
+- Ajouter OneTrueBrace pour les if, while, for, else ... (Gustavo Carreno <gcarreno@netvisao.pt>, Richard Bateman <richard@randyb.byu.edu>, Yaroslav Shvetsov <yaro@totaldesign.ru>, Chris Small <chris@owta.net>)
+- Remove blank lines (Sergio Marchesini <smarques@tin.it>)
+- Forcer une ligne vide apr�s une d�claration de fonction (Richard Bateman <richard@randyb.byu.edu>)
+
-<?php // $Id$\r
- // expired.php - called by hive when the session has expired.\r
-\r
- require('../../config.php');\r
-\r
- require('lib.php');\r
-\r
- require_login();\r
-\r
- //MW theres no easy way to log in seamlessly. We need the users unhashed password.\r
- // It's a security risk to carry that in $SESSION so we put up login form.\r
- print_header();\r
- notify('Your session has expired. Please log in again.'); \r
-?>\r
- <form action="login.php" method="post" name="login" id="login">\r
- <table border="0" align="center">\r
- <tr>\r
- <td width="80%">\r
- <table align="center" class="loginform">\r
- <tr class="username">\r
- <td align="right" class="c0">\r
- <?php print_string("username") ?>:\r
- </td>\r
- <td class="c1">\r
- <input type="text" name="username" size="15" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />\r
- </td>\r
- </tr>\r
- <tr class="password">\r
- <td align="right" class="c0">\r
- <?php print_string("password") ?>:\r
- </td>\r
- <td class="c1">\r
- <input type="password" name="password" size="15" value="" alt="<?php print_string("password") ?>" />\r
- </td>\r
- </tr>\r
- </table>\r
- </td>\r
- <td width="20%">\r
- <input type="submit" value="<?php print_string("login") ?>" />\r
- </td>\r
- </tr>\r
- </table>\r
- </form>\r
-<br />\r
-<?php\r
- close_window_button();\r
-?>\r
+<?php // $Id$
+ // expired.php - called by hive when the session has expired.
+
+ require('../../config.php');
+
+ require('lib.php');
+
+ require_login();
+
+ //MW theres no easy way to log in seamlessly. We need the users unhashed password.
+ // It's a security risk to carry that in $SESSION so we put up login form.
+ print_header();
+ notify('Your session has expired. Please log in again.');
+?>
+ <form action="login.php" method="post" name="login" id="login">
+ <table border="0" align="center">
+ <tr>
+ <td width="80%">
+ <table align="center" class="loginform">
+ <tr class="username">
+ <td align="right" class="c0">
+ <?php print_string("username") ?>:
+ </td>
+ <td class="c1">
+ <input type="text" name="username" size="15" value="<?php p($frm->username) ?>" alt="<?php print_string("username") ?>" />
+ </td>
+ </tr>
+ <tr class="password">
+ <td align="right" class="c0">
+ <?php print_string("password") ?>:
+ </td>
+ <td class="c1">
+ <input type="password" name="password" size="15" value="" alt="<?php print_string("password") ?>" />
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td width="20%">
+ <input type="submit" value="<?php print_string("login") ?>" />
+ </td>
+ </tr>
+ </table>
+ </form>
+<br />
+<?php
+ close_window_button();
+?>
-<?php // $Id$\r
- // Logs into Hive from HarvestRoad and stores session ID in Moodle session\r
- // Martin Dougiamas, Moodle\r
- //\r
- // Example CFG variables to make this work:\r
-\r
- // $CFG->sso = 'hive';\r
- // $CFG->hiveprotocol = 'http';\r
- // $CFG->hiveport = '80';\r
- // $CFG->hivehost = 'turkey.harvestroad.com.au';\r
- // $CFG->hivepath = '/cgi-bin/hive/hive.cgi';\r
- // $CFG->hivecbid = '28';\r
-\r
-function sso_user_login($username, $password) {\r
-\r
- global $CFG, $SESSION;\r
-\r
- include($CFG->libdir.'/snoopy/Snoopy.class.inc');\r
-\r
- if (empty($CFG->hivehost)) {\r
- return false; // Hive config variables not configured yet\r
- }\r
-\r
-/// Set up Snoopy\r
-\r
- $snoopy = new Snoopy;\r
-\r
- $submit_url = $CFG->hiveprotocol .'://'. $CFG->hivehost .':'. $CFG->hiveport .''. $CFG->hivepath ;\r
-\r
- $submit_vars['HIVE_UNAME'] = $username;\r
- $submit_vars['HIVE_UPASS'] = $password;\r
- $submit_vars['HIVE_ENDUSER']= $username;\r
- $submit_vars['HIVE_REQ'] = '2112';\r
- $submit_vars['HIVE_REF'] = 'hin:hive@API Login 3';\r
- $submit_vars['HIVE_RET'] = 'ORG';\r
- $submit_vars['HIVE_REM'] = '';\r
- $submit_vars['HIVE_PROD'] = '0';\r
- $submit_vars['HIVE_USERIP'] = getremoteaddr();\r
-\r
-\r
-/// We use POST to call Hive with a bit more security\r
- $snoopy->submit($submit_url,$submit_vars);\r
-\r
-/// Extract HIVE_SESSION from headers\r
-\r
- foreach ($snoopy->headers as $header) {\r
- if (strpos($header, 'HIVE_SESSION=') !== false) {\r
- $header = explode('HIVE_SESSION=', $header);\r
- if (count($header) > 1) {\r
- $cookie = explode(';', $header[1]);\r
- $cookie = $cookie[0];\r
- $SESSION->HIVE_SESSION = $cookie;\r
- return true;\r
- }\r
- }\r
- }\r
-\r
-/// Try again with the guest username and password\r
-\r
- $submit_vars['HIVE_UNAME'] = $CFG->hiveusername;\r
- $submit_vars['HIVE_UPASS'] = $CFG->hivepassword;\r
- $submit_vars['HIVE_ENDUSER']= $CFG->hiveusername;\r
- $snoopy->submit($submit_url,$submit_vars);\r
- foreach ($snoopy->headers as $header) {\r
- if (strpos($header, 'HIVE_SESSION=') !== false) {\r
- $header = explode('HIVE_SESSION=', $header);\r
- if (count($header) > 1) {\r
- $cookie = explode(';', $header[1]);\r
- $cookie = $cookie[0];\r
- $SESSION->HIVE_SESSION = $cookie;\r
- return true;\r
- }\r
- }\r
- }\r
-\r
- return false; // No cookie found\r
-}\r
-\r
-?>\r
+<?php // $Id$
+ // Logs into Hive from HarvestRoad and stores session ID in Moodle session
+ // Martin Dougiamas, Moodle
+ //
+ // Example CFG variables to make this work:
+
+ // $CFG->sso = 'hive';
+ // $CFG->hiveprotocol = 'http';
+ // $CFG->hiveport = '80';
+ // $CFG->hivehost = 'turkey.harvestroad.com.au';
+ // $CFG->hivepath = '/cgi-bin/hive/hive.cgi';
+ // $CFG->hivecbid = '28';
+
+function sso_user_login($username, $password) {
+
+ global $CFG, $SESSION;
+
+ include($CFG->libdir.'/snoopy/Snoopy.class.inc');
+
+ if (empty($CFG->hivehost)) {
+ return false; // Hive config variables not configured yet
+ }
+
+/// Set up Snoopy
+
+ $snoopy = new Snoopy;
+
+ $submit_url = $CFG->hiveprotocol .'://'. $CFG->hivehost .':'. $CFG->hiveport .''. $CFG->hivepath ;
+
+ $submit_vars['HIVE_UNAME'] = $username;
+ $submit_vars['HIVE_UPASS'] = $password;
+ $submit_vars['HIVE_ENDUSER']= $username;
+ $submit_vars['HIVE_REQ'] = '2112';
+ $submit_vars['HIVE_REF'] = 'hin:hive@API Login 3';
+ $submit_vars['HIVE_RET'] = 'ORG';
+ $submit_vars['HIVE_REM'] = '';
+ $submit_vars['HIVE_PROD'] = '0';
+ $submit_vars['HIVE_USERIP'] = getremoteaddr();
+
+
+/// We use POST to call Hive with a bit more security
+ $snoopy->submit($submit_url,$submit_vars);
+
+/// Extract HIVE_SESSION from headers
+
+ foreach ($snoopy->headers as $header) {
+ if (strpos($header, 'HIVE_SESSION=') !== false) {
+ $header = explode('HIVE_SESSION=', $header);
+ if (count($header) > 1) {
+ $cookie = explode(';', $header[1]);
+ $cookie = $cookie[0];
+ $SESSION->HIVE_SESSION = $cookie;
+ return true;
+ }
+ }
+ }
+
+/// Try again with the guest username and password
+
+ $submit_vars['HIVE_UNAME'] = $CFG->hiveusername;
+ $submit_vars['HIVE_UPASS'] = $CFG->hivepassword;
+ $submit_vars['HIVE_ENDUSER']= $CFG->hiveusername;
+ $snoopy->submit($submit_url,$submit_vars);
+ foreach ($snoopy->headers as $header) {
+ if (strpos($header, 'HIVE_SESSION=') !== false) {
+ $header = explode('HIVE_SESSION=', $header);
+ if (count($header) > 1) {
+ $cookie = explode(';', $header[1]);
+ $cookie = $cookie[0];
+ $SESSION->HIVE_SESSION = $cookie;
+ return true;
+ }
+ }
+ }
+
+ return false; // No cookie found
+}
+
+?>
-<?php // $Id$\r
- // login.php - action of the login form put up by expired.php.\r
-\r
- require('../../config.php');\r
-\r
- require('lib.php');\r
-\r
- require_login();\r
-\r
- // get the login data \r
- $frm = data_submitted('');\r
-\r
- // log back into Hive\r
- if (sso_user_login($frm->username, $frm->password)) { \r
-\r
- /// reopen Hive\r
- redirect($CFG->wwwroot.'/mod/resource/type/repository/hive/openlitebrowse.php');\r
- } else {\r
- redirect($CFG->wwwroot.'/sso/hive/expired.php');\r
- }\r
-\r
-?>\r
-\r
+<?php // $Id$
+ // login.php - action of the login form put up by expired.php.
+
+ require('../../config.php');
+
+ require('lib.php');
+
+ require_login();
+
+ // get the login data
+ $frm = data_submitted('');
+
+ // log back into Hive
+ if (sso_user_login($frm->username, $frm->password)) {
+
+ /// reopen Hive
+ redirect($CFG->wwwroot.'/mod/resource/type/repository/hive/openlitebrowse.php');
+ } else {
+ redirect($CFG->wwwroot.'/sso/hive/expired.php');
+ }
+
+?>
+
-ACTIVITY MODULES\r
-----------------\r
-\r
-These are main modules in Moodle, allowing various activities.\r
-\r
-\r
-Each of these modules contains a number of expected components:\r
-\r
- mod.html: a form to setup/update a module instance\r
-\r
- version.php: defines some meta-info and provides upgrading code\r
-\r
- icon.gif: a 16x16 icon for the module\r
-\r
- db/mysql.sql: an SQL dump of all the required db tables and data\r
- \r
- index.php: a page to list all instances in a course\r
-\r
- view.php: a page to view a particular instance\r
-\r
- lib.php: any/all functions defined by the module should be in here.\r
- constants should be defined using MODULENAME_xxxxxx\r
- functions should be defined using modulename_xxxxxx\r
-\r
- There are a number of standard functions:\r
-\r
- modulename_add_instance()\r
- modulename_update_instance()\r
- modulename_delete_instance()\r
-\r
- modulename_user_complete()\r
- modulename_user_outline()\r
-\r
- modulename_cron()\r
-\r
- modulename_print_recent_activity()\r
-\r
-\r
-If you are a developer and interested in developing new Modules see:\r
- \r
- Moodle Documentation: http://moodle.org/doc\r
- Moodle Community: http://moodle.org/community\r
+ACTIVITY MODULES
+----------------
+
+These are main modules in Moodle, allowing various activities.
+
+
+Each of these modules contains a number of expected components:
+
+ mod.html: a form to setup/update a module instance
+
+ version.php: defines some meta-info and provides upgrading code
+
+ icon.gif: a 16x16 icon for the module
+
+ db/mysql.sql: an SQL dump of all the required db tables and data
+
+ index.php: a page to list all instances in a course
+
+ view.php: a page to view a particular instance
+
+ lib.php: any/all functions defined by the module should be in here.
+ constants should be defined using MODULENAME_xxxxxx
+ functions should be defined using modulename_xxxxxx
+
+ There are a number of standard functions:
+
+ modulename_add_instance()
+ modulename_update_instance()
+ modulename_delete_instance()
+
+ modulename_user_complete()
+ modulename_user_outline()
+
+ modulename_cron()
+
+ modulename_print_recent_activity()
+
+
+If you are a developer and interested in developing new Modules see:
+
+ Moodle Documentation: http://moodle.org/doc
+ Moodle Community: http://moodle.org/community
-/*\r
- cssQuery, version 2.0.2 (2005-08-19)\r
- Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)\r
- License: http://creativecommons.org/licenses/LGPL/2.1/\r
-*/\r
-\r
-// the following functions allow querying of the DOM using CSS selectors\r
-var cssQuery = function() {\r
-var version = "2.0.2";\r
-\r
-// -----------------------------------------------------------------------\r
-// main query function\r
-// -----------------------------------------------------------------------\r
-\r
-var $COMMA = /\s*,\s*/;\r
-var cssQuery = function($selector, $$from) {\r
-try {\r
- var $match = [];\r
- var $useCache = arguments.callee.caching && !$$from;\r
- var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];\r
- // process comma separated selectors\r
- var $$selectors = parseSelector($selector).split($COMMA), i;\r
- for (i = 0; i < $$selectors.length; i++) {\r
- // convert the selector to a stream\r
- $selector = _toStream($$selectors[i]);\r
- // faster chop if it starts with id (MSIE only)\r
- if (isMSIE && $selector.slice(0, 3).join("") == " *#") {\r
- $selector = $selector.slice(2);\r
- $$from = _msie_selectById([], $base, $selector[1]);\r
- } else $$from = $base;\r
- // process the stream\r
- var j = 0, $token, $filter, $arguments, $cacheSelector = "";\r
- while (j < $selector.length) {\r
- $token = $selector[j++];\r
- $filter = $selector[j++];\r
- $cacheSelector += $token + $filter;\r
- // some pseudo-classes allow arguments to be passed\r
- // e.g. nth-child(even)\r
- $arguments = "";\r
- if ($selector[j] == "(") {\r
- while ($selector[j++] != ")" && j < $selector.length) {\r
- $arguments += $selector[j];\r
- }\r
- $arguments = $arguments.slice(0, -1);\r
- $cacheSelector += "(" + $arguments + ")";\r
- }\r
- // process a token/filter pair use cached results if possible\r
- $$from = ($useCache && cache[$cacheSelector]) ?\r
- cache[$cacheSelector] : select($$from, $token, $filter, $arguments);\r
- if ($useCache) cache[$cacheSelector] = $$from;\r
- }\r
- $match = $match.concat($$from);\r
- }\r
- delete cssQuery.error;\r
- return $match;\r
-} catch ($error) {\r
- cssQuery.error = $error;\r
- return [];\r
-}};\r
-\r
-// -----------------------------------------------------------------------\r
-// public interface\r
-// -----------------------------------------------------------------------\r
-\r
-cssQuery.toString = function() {\r
- return "function cssQuery() {\n [version " + version + "]\n}";\r
-};\r
-\r
-// caching\r
-var cache = {};\r
-cssQuery.caching = false;\r
-cssQuery.clearCache = function($selector) {\r
- if ($selector) {\r
- $selector = _toStream($selector).join("");\r
- delete cache[$selector];\r
- } else cache = {};\r
-};\r
-\r
-// allow extensions\r
-var modules = {};\r
-var loaded = false;\r
-cssQuery.addModule = function($name, $script) {\r
- if (loaded) eval("$script=" + String($script));\r
- modules[$name] = new $script();;\r
-};\r
-\r
-// hackery\r
-cssQuery.valueOf = function($code) {\r
- return $code ? eval($code) : this;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// declarations\r
-// -----------------------------------------------------------------------\r
-\r
-var selectors = {};\r
-var pseudoClasses = {};\r
-// a safari bug means that these have to be declared here\r
-var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};\r
-var attributeSelectors = [];\r
-\r
-// -----------------------------------------------------------------------\r
-// selectors\r
-// -----------------------------------------------------------------------\r
-\r
-// descendant selector\r
-selectors[" "] = function($results, $from, $tagName, $namespace) {\r
- // loop through current selection\r
- var $element, i, j;\r
- for (i = 0; i < $from.length; i++) {\r
- // get descendants\r
- var $subset = getElementsByTagName($from[i], $tagName, $namespace);\r
- // loop through descendants and add to results selection\r
- for (j = 0; ($element = $subset[j]); j++) {\r
- if (thisElement($element) && compareNamespace($element, $namespace))\r
- $results.push($element);\r
- }\r
- }\r
-};\r
-\r
-// ID selector\r
-selectors["#"] = function($results, $from, $id) {\r
- // loop through current selection and check ID\r
- var $element, j;\r
- for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);\r
-};\r
-\r
-// class selector\r
-selectors["."] = function($results, $from, $className) {\r
- // create a RegExp version of the class\r
- $className = new RegExp("(^|\\s)" + $className + "(\\s|$)");\r
- // loop through current selection and check class\r
- var $element, i;\r
- for (i = 0; ($element = $from[i]); i++)\r
- if ($className.test($element.className)) $results.push($element);\r
-};\r
-\r
-// pseudo-class selector\r
-selectors[":"] = function($results, $from, $pseudoClass, $arguments) {\r
- // retrieve the cssQuery pseudo-class function\r
- var $test = pseudoClasses[$pseudoClass], $element, i;\r
- // loop through current selection and apply pseudo-class filter\r
- if ($test) for (i = 0; ($element = $from[i]); i++)\r
- // if the cssQuery pseudo-class function returns "true" add the element\r
- if ($test($element, $arguments)) $results.push($element);\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// pseudo-classes\r
-// -----------------------------------------------------------------------\r
-\r
-pseudoClasses["link"] = function($element) {\r
- var $document = getDocument($element);\r
- if ($document.links) for (var i = 0; i < $document.links.length; i++) {\r
- if ($document.links[i] == $element) return true;\r
- }\r
-};\r
-\r
-pseudoClasses["visited"] = function($element) {\r
- // can't do this without jiggery-pokery\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// DOM traversal\r
-// -----------------------------------------------------------------------\r
-\r
-// IE5/6 includes comments (LOL) in it's elements collections.\r
-// so we have to check for this. the test is tagName != "!". LOL (again).\r
-var thisElement = function($element) {\r
- return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;\r
-};\r
-\r
-// return the previous element to the supplied element\r
-// previousSibling is not good enough as it might return a text or comment node\r
-var previousElementSibling = function($element) {\r
- while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;\r
- return $element;\r
-};\r
-\r
-// return the next element to the supplied element\r
-var nextElementSibling = function($element) {\r
- while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;\r
- return $element;\r
-};\r
-\r
-// return the first child ELEMENT of an element\r
-// NOT the first child node (though they may be the same thing)\r
-var firstElementChild = function($element) {\r
- return thisElement($element.firstChild) || nextElementSibling($element.firstChild);\r
-};\r
-\r
-var lastElementChild = function($element) {\r
- return thisElement($element.lastChild) || previousElementSibling($element.lastChild);\r
-};\r
-\r
-// return child elements of an element (not child nodes)\r
-var childElements = function($element) {\r
- var $childElements = [];\r
- $element = firstElementChild($element);\r
- while ($element) {\r
- $childElements.push($element);\r
- $element = nextElementSibling($element);\r
- }\r
- return $childElements;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// browser compatibility\r
-// -----------------------------------------------------------------------\r
-\r
-// all of the functions in this section can be overwritten. the default\r
-// configuration is for IE. The functions below reflect this. standard\r
-// methods are included in a separate module. It would probably be better\r
-// the other way round of course but this makes it easier to keep IE7 trim.\r
-\r
-var isMSIE = true;\r
-\r
-var isXML = function($element) {\r
- var $document = getDocument($element);\r
- return (typeof $document.mimeType == "unknown") ?\r
- /\.xml$/i.test($document.URL) :\r
- Boolean($document.mimeType == "XML Document");\r
-};\r
-\r
-// return the element's containing document\r
-var getDocument = function($element) {\r
- return $element.ownerDocument || $element.document;\r
-};\r
-\r
-var getElementsByTagName = function($element, $tagName) {\r
- return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);\r
-};\r
-\r
-var compareTagName = function($element, $tagName, $namespace) {\r
- if ($tagName == "*") return thisElement($element);\r
- if (!compareNamespace($element, $namespace)) return false;\r
- if (!isXML($element)) $tagName = $tagName.toUpperCase();\r
- return $element.tagName == $tagName;\r
-};\r
-\r
-var compareNamespace = function($element, $namespace) {\r
- return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);\r
-};\r
-\r
-var getTextContent = function($element) {\r
- return $element.innerText;\r
-};\r
-\r
-function _msie_selectById($results, $from, id) {\r
- var $match, i, j;\r
- for (i = 0; i < $from.length; i++) {\r
- if ($match = $from[i].all.item(id)) {\r
- if ($match.id == id) $results.push($match);\r
- else if ($match.length != null) {\r
- for (j = 0; j < $match.length; j++) {\r
- if ($match[j].id == id) $results.push($match[j]);\r
- }\r
- }\r
- }\r
- }\r
- return $results;\r
-};\r
-\r
-// for IE5.0\r
-if (![].push) Array.prototype.push = function() {\r
- for (var i = 0; i < arguments.length; i++) {\r
- this[this.length] = arguments[i];\r
- }\r
- return this.length;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// query support\r
-// -----------------------------------------------------------------------\r
-\r
-// select a set of matching elements.\r
-// "from" is an array of elements.\r
-// "token" is a character representing the type of filter\r
-// e.g. ">" means child selector\r
-// "filter" represents the tag name, id or class name that is being selected\r
-// the function returns an array of matching elements\r
-var $NAMESPACE = /\|/;\r
-function select($$from, $token, $filter, $arguments) {\r
- if ($NAMESPACE.test($filter)) {\r
- $filter = $filter.split($NAMESPACE);\r
- $arguments = $filter[0];\r
- $filter = $filter[1];\r
- }\r
- var $results = [];\r
- if (selectors[$token]) {\r
- selectors[$token]($results, $$from, $filter, $arguments);\r
- }\r
- return $results;\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// parsing\r
-// -----------------------------------------------------------------------\r
-\r
-// convert css selectors to a stream of tokens and filters\r
-// it's not a real stream. it's just an array of strings.\r
-var $STANDARD_SELECT = /^[^\s>+~]/;\r
-var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;\r
-function _toStream($selector) {\r
- if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;\r
- return $selector.match($$STREAM) || [];\r
-};\r
-\r
-var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;\r
-var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;\r
-var parseSelector = function($selector) {\r
- return $selector\r
- // trim whitespace\r
- .replace($WHITESPACE, "$1")\r
- // e.g. ".class1" --> "*.class1"\r
- .replace($IMPLIED_ALL, "$1*$2");\r
-};\r
-\r
-var Quote = {\r
- toString: function() {return "'"},\r
- match: /^('[^']*')|("[^"]*")$/,\r
- test: function($string) {\r
- return this.match.test($string);\r
- },\r
- add: function($string) {\r
- return this.test($string) ? $string : this + $string + this;\r
- },\r
- remove: function($string) {\r
- return this.test($string) ? $string.slice(1, -1) : $string;\r
- }\r
-};\r
-\r
-var getText = function($text) {\r
- return Quote.remove($text);\r
-};\r
-\r
-var $ESCAPE = /([\/()[\]?{}|*+-])/g;\r
-function regEscape($string) {\r
- return $string.replace($ESCAPE, "\\$1");\r
-};\r
-\r
-// -----------------------------------------------------------------------\r
-// modules\r
-// -----------------------------------------------------------------------\r
-\r
-// -------- >> insert modules here for packaging << -------- \\\r
-\r
-loaded = true;\r
-\r
-// -----------------------------------------------------------------------\r
-// return the query function\r
-// -----------------------------------------------------------------------\r
-\r
-return cssQuery;\r
-\r
-}(); // cssQuery\r
+/*
+ cssQuery, version 2.0.2 (2005-08-19)
+ Copyright: 2004-2005, Dean Edwards (http://dean.edwards.name/)
+ License: http://creativecommons.org/licenses/LGPL/2.1/
+*/
+
+// the following functions allow querying of the DOM using CSS selectors
+var cssQuery = function() {
+var version = "2.0.2";
+
+// -----------------------------------------------------------------------
+// main query function
+// -----------------------------------------------------------------------
+
+var $COMMA = /\s*,\s*/;
+var cssQuery = function($selector, $$from) {
+try {
+ var $match = [];
+ var $useCache = arguments.callee.caching && !$$from;
+ var $base = ($$from) ? ($$from.constructor == Array) ? $$from : [$$from] : [document];
+ // process comma separated selectors
+ var $$selectors = parseSelector($selector).split($COMMA), i;
+ for (i = 0; i < $$selectors.length; i++) {
+ // convert the selector to a stream
+ $selector = _toStream($$selectors[i]);
+ // faster chop if it starts with id (MSIE only)
+ if (isMSIE && $selector.slice(0, 3).join("") == " *#") {
+ $selector = $selector.slice(2);
+ $$from = _msie_selectById([], $base, $selector[1]);
+ } else $$from = $base;
+ // process the stream
+ var j = 0, $token, $filter, $arguments, $cacheSelector = "";
+ while (j < $selector.length) {
+ $token = $selector[j++];
+ $filter = $selector[j++];
+ $cacheSelector += $token + $filter;
+ // some pseudo-classes allow arguments to be passed
+ // e.g. nth-child(even)
+ $arguments = "";
+ if ($selector[j] == "(") {
+ while ($selector[j++] != ")" && j < $selector.length) {
+ $arguments += $selector[j];
+ }
+ $arguments = $arguments.slice(0, -1);
+ $cacheSelector += "(" + $arguments + ")";
+ }
+ // process a token/filter pair use cached results if possible
+ $$from = ($useCache && cache[$cacheSelector]) ?
+ cache[$cacheSelector] : select($$from, $token, $filter, $arguments);
+ if ($useCache) cache[$cacheSelector] = $$from;
+ }
+ $match = $match.concat($$from);
+ }
+ delete cssQuery.error;
+ return $match;
+} catch ($error) {
+ cssQuery.error = $error;
+ return [];
+}};
+
+// -----------------------------------------------------------------------
+// public interface
+// -----------------------------------------------------------------------
+
+cssQuery.toString = function() {
+ return "function cssQuery() {\n [version " + version + "]\n}";
+};
+
+// caching
+var cache = {};
+cssQuery.caching = false;
+cssQuery.clearCache = function($selector) {
+ if ($selector) {
+ $selector = _toStream($selector).join("");
+ delete cache[$selector];
+ } else cache = {};
+};
+
+// allow extensions
+var modules = {};
+var loaded = false;
+cssQuery.addModule = function($name, $script) {
+ if (loaded) eval("$script=" + String($script));
+ modules[$name] = new $script();;
+};
+
+// hackery
+cssQuery.valueOf = function($code) {
+ return $code ? eval($code) : this;
+};
+
+// -----------------------------------------------------------------------
+// declarations
+// -----------------------------------------------------------------------
+
+var selectors = {};
+var pseudoClasses = {};
+// a safari bug means that these have to be declared here
+var AttributeSelector = {match: /\[([\w-]+(\|[\w-]+)?)\s*(\W?=)?\s*([^\]]*)\]/};
+var attributeSelectors = [];
+
+// -----------------------------------------------------------------------
+// selectors
+// -----------------------------------------------------------------------
+
+// descendant selector
+selectors[" "] = function($results, $from, $tagName, $namespace) {
+ // loop through current selection
+ var $element, i, j;
+ for (i = 0; i < $from.length; i++) {
+ // get descendants
+ var $subset = getElementsByTagName($from[i], $tagName, $namespace);
+ // loop through descendants and add to results selection
+ for (j = 0; ($element = $subset[j]); j++) {
+ if (thisElement($element) && compareNamespace($element, $namespace))
+ $results.push($element);
+ }
+ }
+};
+
+// ID selector
+selectors["#"] = function($results, $from, $id) {
+ // loop through current selection and check ID
+ var $element, j;
+ for (j = 0; ($element = $from[j]); j++) if ($element.id == $id) $results.push($element);
+};
+
+// class selector
+selectors["."] = function($results, $from, $className) {
+ // create a RegExp version of the class
+ $className = new RegExp("(^|\\s)" + $className + "(\\s|$)");
+ // loop through current selection and check class
+ var $element, i;
+ for (i = 0; ($element = $from[i]); i++)
+ if ($className.test($element.className)) $results.push($element);
+};
+
+// pseudo-class selector
+selectors[":"] = function($results, $from, $pseudoClass, $arguments) {
+ // retrieve the cssQuery pseudo-class function
+ var $test = pseudoClasses[$pseudoClass], $element, i;
+ // loop through current selection and apply pseudo-class filter
+ if ($test) for (i = 0; ($element = $from[i]); i++)
+ // if the cssQuery pseudo-class function returns "true" add the element
+ if ($test($element, $arguments)) $results.push($element);
+};
+
+// -----------------------------------------------------------------------
+// pseudo-classes
+// -----------------------------------------------------------------------
+
+pseudoClasses["link"] = function($element) {
+ var $document = getDocument($element);
+ if ($document.links) for (var i = 0; i < $document.links.length; i++) {
+ if ($document.links[i] == $element) return true;
+ }
+};
+
+pseudoClasses["visited"] = function($element) {
+ // can't do this without jiggery-pokery
+};
+
+// -----------------------------------------------------------------------
+// DOM traversal
+// -----------------------------------------------------------------------
+
+// IE5/6 includes comments (LOL) in it's elements collections.
+// so we have to check for this. the test is tagName != "!". LOL (again).
+var thisElement = function($element) {
+ return ($element && $element.nodeType == 1 && $element.tagName != "!") ? $element : null;
+};
+
+// return the previous element to the supplied element
+// previousSibling is not good enough as it might return a text or comment node
+var previousElementSibling = function($element) {
+ while ($element && ($element = $element.previousSibling) && !thisElement($element)) continue;
+ return $element;
+};
+
+// return the next element to the supplied element
+var nextElementSibling = function($element) {
+ while ($element && ($element = $element.nextSibling) && !thisElement($element)) continue;
+ return $element;
+};
+
+// return the first child ELEMENT of an element
+// NOT the first child node (though they may be the same thing)
+var firstElementChild = function($element) {
+ return thisElement($element.firstChild) || nextElementSibling($element.firstChild);
+};
+
+var lastElementChild = function($element) {
+ return thisElement($element.lastChild) || previousElementSibling($element.lastChild);
+};
+
+// return child elements of an element (not child nodes)
+var childElements = function($element) {
+ var $childElements = [];
+ $element = firstElementChild($element);
+ while ($element) {
+ $childElements.push($element);
+ $element = nextElementSibling($element);
+ }
+ return $childElements;
+};
+
+// -----------------------------------------------------------------------
+// browser compatibility
+// -----------------------------------------------------------------------
+
+// all of the functions in this section can be overwritten. the default
+// configuration is for IE. The functions below reflect this. standard
+// methods are included in a separate module. It would probably be better
+// the other way round of course but this makes it easier to keep IE7 trim.
+
+var isMSIE = true;
+
+var isXML = function($element) {
+ var $document = getDocument($element);
+ return (typeof $document.mimeType == "unknown") ?
+ /\.xml$/i.test($document.URL) :
+ Boolean($document.mimeType == "XML Document");
+};
+
+// return the element's containing document
+var getDocument = function($element) {
+ return $element.ownerDocument || $element.document;
+};
+
+var getElementsByTagName = function($element, $tagName) {
+ return ($tagName == "*" && $element.all) ? $element.all : $element.getElementsByTagName($tagName);
+};
+
+var compareTagName = function($element, $tagName, $namespace) {
+ if ($tagName == "*") return thisElement($element);
+ if (!compareNamespace($element, $namespace)) return false;
+ if (!isXML($element)) $tagName = $tagName.toUpperCase();
+ return $element.tagName == $tagName;
+};
+
+var compareNamespace = function($element, $namespace) {
+ return !$namespace || ($namespace == "*") || ($element.scopeName == $namespace);
+};
+
+var getTextContent = function($element) {
+ return $element.innerText;
+};
+
+function _msie_selectById($results, $from, id) {
+ var $match, i, j;
+ for (i = 0; i < $from.length; i++) {
+ if ($match = $from[i].all.item(id)) {
+ if ($match.id == id) $results.push($match);
+ else if ($match.length != null) {
+ for (j = 0; j < $match.length; j++) {
+ if ($match[j].id == id) $results.push($match[j]);
+ }
+ }
+ }
+ }
+ return $results;
+};
+
+// for IE5.0
+if (![].push) Array.prototype.push = function() {
+ for (var i = 0; i < arguments.length; i++) {
+ this[this.length] = arguments[i];
+ }
+ return this.length;
+};
+
+// -----------------------------------------------------------------------
+// query support
+// -----------------------------------------------------------------------
+
+// select a set of matching elements.
+// "from" is an array of elements.
+// "token" is a character representing the type of filter
+// e.g. ">" means child selector
+// "filter" represents the tag name, id or class name that is being selected
+// the function returns an array of matching elements
+var $NAMESPACE = /\|/;
+function select($$from, $token, $filter, $arguments) {
+ if ($NAMESPACE.test($filter)) {
+ $filter = $filter.split($NAMESPACE);
+ $arguments = $filter[0];
+ $filter = $filter[1];
+ }
+ var $results = [];
+ if (selectors[$token]) {
+ selectors[$token]($results, $$from, $filter, $arguments);
+ }
+ return $results;
+};
+
+// -----------------------------------------------------------------------
+// parsing
+// -----------------------------------------------------------------------
+
+// convert css selectors to a stream of tokens and filters
+// it's not a real stream. it's just an array of strings.
+var $STANDARD_SELECT = /^[^\s>+~]/;
+var $$STREAM = /[\s#.:>+~()@]|[^\s#.:>+~()@]+/g;
+function _toStream($selector) {
+ if ($STANDARD_SELECT.test($selector)) $selector = " " + $selector;
+ return $selector.match($$STREAM) || [];
+};
+
+var $WHITESPACE = /\s*([\s>+~(),]|^|$)\s*/g;
+var $IMPLIED_ALL = /([\s>+~,]|[^(]\+|^)([#.:@])/g;
+var parseSelector = function($selector) {
+ return $selector
+ // trim whitespace
+ .replace($WHITESPACE, "$1")
+ // e.g. ".class1" --> "*.class1"
+ .replace($IMPLIED_ALL, "$1*$2");
+};
+
+var Quote = {
+ toString: function() {return "'"},
+ match: /^('[^']*')|("[^"]*")$/,
+ test: function($string) {
+ return this.match.test($string);
+ },
+ add: function($string) {
+ return this.test($string) ? $string : this + $string + this;
+ },
+ remove: function($string) {
+ return this.test($string) ? $string.slice(1, -1) : $string;
+ }
+};
+
+var getText = function($text) {
+ return Quote.remove($text);
+};
+
+var $ESCAPE = /([\/()[\]?{}|*+-])/g;
+function regEscape($string) {
+ return $string.replace($ESCAPE, "\\$1");
+};
+
+// -----------------------------------------------------------------------
+// modules
+// -----------------------------------------------------------------------
+
+// -------- >> insert modules here for packaging << -------- \\
+
+loaded = true;
+
+// -----------------------------------------------------------------------
+// return the query function
+// -----------------------------------------------------------------------
+
+return cssQuery;
+
+}(); // cssQuery
-\r
-/**\r
- * ====================================================================\r
- * About\r
- * ====================================================================\r
- * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.\r
- * The library supports Gecko based browsers like Mozilla and Firefox,\r
- * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera\r
- * @version 0.9.6.1\r
- * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net\r
- * ====================================================================\r
- * Licence\r
- * ====================================================================\r
- * This program is free software; you can redistribute it and/or modify\r
- * it under the terms of the GNU General Public License version 2 or\r
- * the GNU Lesser General Public License version 2.1 as published by\r
- * the Free Software Foundation (your choice between the two).\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
- * GNU General Public License or GNU Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * or GNU Lesser General Public License along with this program; if not,\r
- * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- * or visit http://www.gnu.org\r
- *\r
- */\r
-/**\r
- * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and \r
- * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>\r
- * @constructor\r
- */\r
-function Sarissa(){};\r
-/** @private */\r
-Sarissa.PARSED_OK = "Document contains no parsing errors";\r
-/**\r
- * Tells you whether transformNode and transformNodeToObject are available. This functionality\r
- * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations\r
- * use the XSLTProcessor\r
- * @deprecated\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_TRANSFORM_NODE = false;\r
-/**\r
- * tells you whether XMLHttpRequest (or equivalent) is available\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_XMLHTTP = false;\r
-/**\r
- * tells you whether selectNodes/selectSingleNode is available\r
- * @type boolean\r
- */\r
-Sarissa.IS_ENABLED_SELECT_NODES = false;\r
-var _sarissa_iNsCounter = 0;\r
-var _SARISSA_IEPREFIX4XSLPARAM = "";\r
-var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;\r
-var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;\r
-var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;\r
-var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;\r
-var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));\r
-var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1;\r
-if(!window.Node || !window.Node.ELEMENT_NODE){\r
- var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};\r
-};\r
-\r
-// IE initialization\r
-if(_SARISSA_IS_IE){\r
- // for XSLT parameter names, prefix needed by IE\r
- _SARISSA_IEPREFIX4XSLPARAM = "xsl:";\r
- // used to store the most recent ProgID available out of the above\r
- var _SARISSA_DOM_PROGID = "";\r
- var _SARISSA_XMLHTTP_PROGID = "";\r
- /**\r
- * Called when the Sarissa_xx.js file is parsed, to pick most recent\r
- * ProgIDs for IE, then gets destroyed.\r
- * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object\r
- * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled\r
- */\r
- pickRecentProgID = function (idList, enabledList){\r
- // found progID flag\r
- var bFound = false;\r
- for(var i=0; i < idList.length && !bFound; i++){\r
- try{\r
- var oDoc = new ActiveXObject(idList[i]);\r
- o2Store = idList[i];\r
- bFound = true;\r
- for(var j=0;j<enabledList.length;j++)\r
- if(i <= enabledList[j][1])\r
- Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;\r
- }catch (objException){\r
- // trap; try next progID\r
- };\r
- };\r
- if (!bFound)\r
- throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";\r
- idList = null;\r
- return o2Store;\r
- };\r
- // pick best available MSXML progIDs\r
- _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);\r
- _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);\r
- _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);\r
- _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);\r
- // we dont need this anymore\r
- pickRecentProgID = null;\r
- //============================================\r
- // Factory methods (IE)\r
- //============================================\r
- // see non-IE version\r
- Sarissa.getDomDocument = function(sUri, sName){\r
- var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);\r
- // if a root tag name was provided, we need to load it in the DOM\r
- // object\r
- if (sName){\r
- // if needed, create an artifical namespace prefix the way Moz\r
- // does\r
- if (sUri){\r
- oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");\r
- // don't use the same prefix again\r
- ++_sarissa_iNsCounter;\r
- }\r
- else\r
- oDoc.loadXML("<" + sName + "/>");\r
- };\r
- return oDoc;\r
- };\r
- // see non-IE version \r
- Sarissa.getParseErrorText = function (oDoc) {\r
- var parseErrorText = Sarissa.PARSED_OK;\r
- if(oDoc.parseError != 0){\r
- parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason + \r
- "\nLocation: " + oDoc.parseError.url + \r
- "\nLine Number " + oDoc.parseError.line + ", Column " + \r
- oDoc.parseError.linepos + \r
- ":\n" + oDoc.parseError.srcText +\r
- "\n";\r
- for(var i = 0; i < oDoc.parseError.linepos;i++){\r
- parseErrorText += "-";\r
- };\r
- parseErrorText += "^\n";\r
- };\r
- return parseErrorText;\r
- };\r
- // see non-IE version\r
- Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {\r
- oDoc.setProperty("SelectionLanguage", "XPath");\r
- oDoc.setProperty("SelectionNamespaces", sNsSet);\r
- }; \r
- /**\r
- * Basic implementation of Mozilla's XSLTProcessor for IE. \r
- * Reuses the same XSLT stylesheet for multiple transforms\r
- * @constructor\r
- */\r
- XSLTProcessor = function(){\r
- this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);\r
- this.processor = null;\r
- };\r
- /**\r
- * Impoprts the given XSLT DOM and compiles it to a reusable transform\r
- * @argument xslDoc The XSLT DOMDocument to import\r
- */\r
- XSLTProcessor.prototype.importStylesheet = function(xslDoc){\r
- // convert stylesheet to free threaded\r
- var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID); \r
- converted.loadXML(xslDoc.xml);\r
- this.template.stylesheet = converted;\r
- this.processor = this.template.createProcessor();\r
- // (re)set default param values\r
- this.paramsSet = new Array();\r
- };\r
- /**\r
- * Transform the given XML DOM\r
- * @argument sourceDoc The XML DOMDocument to transform\r
- * @return The transformation result as a DOM Document\r
- */\r
- XSLTProcessor.prototype.transformToDocument = function(sourceDoc){\r
- this.processor.input = sourceDoc;\r
- var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);\r
- this.processor.output = outDoc; \r
- this.processor.transform();\r
- return outDoc;\r
- };\r
- /**\r
- * Set global XSLT parameter of the imported stylesheet\r
- * @argument nsURI The parameter namespace URI\r
- * @argument name The parameter base name\r
- * @argument value The new parameter value\r
- */\r
- XSLTProcessor.prototype.setParameter = function(nsURI, name, value){\r
- /* nsURI is optional but cannot be null */\r
- if(nsURI){\r
- this.processor.addParameter(name, value, nsURI);\r
- }else{\r
- this.processor.addParameter(name, value);\r
- };\r
- /* update updated params for getParameter */\r
- if(!this.paramsSet[""+nsURI]){\r
- this.paramsSet[""+nsURI] = new Array();\r
- };\r
- this.paramsSet[""+nsURI][name] = value;\r
- };\r
- /**\r
- * Gets a parameter if previously set by setParameter. Returns null\r
- * otherwise\r
- * @argument name The parameter base name\r
- * @argument value The new parameter value\r
- * @return The parameter value if reviously set by setParameter, null otherwise\r
- */\r
- XSLTProcessor.prototype.getParameter = function(nsURI, name){\r
- nsURI = nsURI || "";\r
- if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){\r
- return this.paramsSet[nsURI][name];\r
- }else{\r
- return null;\r
- };\r
- };\r
-}\r
-else{ /* end IE initialization, try to deal with real browsers now ;-) */\r
- if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){\r
- /**\r
- * <p>Ensures the document was loaded correctly, otherwise sets the\r
- * parseError to -1 to indicate something went wrong. Internal use</p>\r
- * @private\r
- */\r
- Sarissa.__handleLoad__ = function(oDoc){\r
- if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")\r
- oDoc.parseError = -1;\r
- Sarissa.__setReadyState__(oDoc, 4);\r
- };\r
- /**\r
- * <p>Attached by an event handler to the load event. Internal use.</p>\r
- * @private\r
- */\r
- _sarissa_XMLDocument_onload = function(){\r
- Sarissa.__handleLoad__(this);\r
- };\r
- /**\r
- * <p>Sets the readyState property of the given DOM Document object.\r
- * Internal use.</p>\r
- * @private\r
- * @argument oDoc the DOM Document object to fire the\r
- * readystatechange event\r
- * @argument iReadyState the number to change the readystate property to\r
- */\r
- Sarissa.__setReadyState__ = function(oDoc, iReadyState){\r
- oDoc.readyState = iReadyState;\r
- if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")\r
- oDoc.onreadystatechange();\r
- };\r
- Sarissa.getDomDocument = function(sUri, sName){\r
- var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);\r
- oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);\r
- return oDoc;\r
- };\r
- if(window.XMLDocument){\r
- /**\r
- * <p>Emulate IE's onreadystatechange attribute</p>\r
- */\r
- XMLDocument.prototype.onreadystatechange = null;\r
- /**\r
- * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>\r
- * <ul><li>1 == LOADING,</li>\r
- * <li>2 == LOADED,</li>\r
- * <li>3 == INTERACTIVE,</li>\r
- * <li>4 == COMPLETED</li></ul>\r
- */\r
- XMLDocument.prototype.readyState = 0;\r
- /**\r
- * <p>Emulate IE's parseError attribute</p>\r
- */\r
- XMLDocument.prototype.parseError = 0;\r
-\r
- // NOTE: setting async to false will only work with documents\r
- // called over HTTP (meaning a server), not the local file system,\r
- // unless you are using Moz 1.4+.\r
- // BTW the try>catch block is for 1.4; I haven't found a way to check if\r
- // the property is implemented without\r
- // causing an error and I dont want to use user agent stuff for that...\r
- var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;\r
- /**\r
- * <p>Keeps a handle to the original load() method. Internal use and only\r
- * if Mozilla version is lower than 1.4</p>\r
- * @private\r
- */\r
- XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;\r
-\r
- /**\r
- * <p>Overrides the original load method to provide synchronous loading for\r
- * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if\r
- * async is set to false)</p>\r
- * @returns the DOM Object as it was before the load() call (may be empty)\r
- */\r
- XMLDocument.prototype.load = function(sURI) {\r
- var oDoc = document.implementation.createDocument("", "", null);\r
- Sarissa.copyChildNodes(this, oDoc);\r
- this.parseError = 0;\r
- Sarissa.__setReadyState__(this, 1);\r
- try {\r
- if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {\r
- var tmp = new XMLHttpRequest();\r
- tmp.open("GET", sURI, false);\r
- tmp.send(null);\r
- Sarissa.__setReadyState__(this, 2);\r
- Sarissa.copyChildNodes(tmp.responseXML, this);\r
- Sarissa.__setReadyState__(this, 3);\r
- }\r
- else {\r
- this._sarissa_load(sURI);\r
- };\r
- }\r
- catch (objException) {\r
- this.parseError = -1;\r
- }\r
- finally {\r
- if(this.async == false){\r
- Sarissa.__handleLoad__(this);\r
- };\r
- };\r
- return oDoc;\r
- };\r
- \r
- \r
- }//if(window.XMLDocument)\r
- else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){\r
- Document.prototype.async = true;\r
- Document.prototype.onreadystatechange = null;\r
- Document.prototype.parseError = 0;\r
- Document.prototype.load = function(sURI) {\r
- var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);\r
- if(this.async){\r
- var self = this;\r
- parser.addEventListener("load", \r
- function(e) { \r
- self.readyState = 4;\r
- Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);\r
- self.onreadystatechange.call(); \r
- }, \r
- false); \r
- };\r
- try {\r
- var oDoc = parser.parseURI(sURI);\r
- }\r
- catch(e){\r
- this.parseError = -1;\r
- };\r
- if(!this.async)\r
- Sarissa.copyChildNodes(oDoc, this.documentElement, false);\r
- return oDoc;\r
- };\r
- /**\r
- * <p>Factory method to obtain a new DOM Document object</p>\r
- * @argument sUri the namespace of the root node (if any)\r
- * @argument sUri the local name of the root node (if any)\r
- * @returns a new DOM Document\r
- */\r
- Sarissa.getDomDocument = function(sUri, sName){\r
- return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);\r
- }; \r
- };\r
- };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)\r
-};\r
-//==========================================\r
-// Common stuff\r
-//==========================================\r
-if(!window.DOMParser){\r
- /*\r
- * DOMParser is a utility class, used to construct DOMDocuments from XML strings\r
- * @constructor\r
- */\r
- DOMParser = function() {\r
- };\r
- if(_SARISSA_IS_SAFARI){\r
- /** \r
- * Construct a new DOM Document from the given XMLstring\r
- * @param sXml the given XML string\r
- * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). \r
- * @return a new DOM Document from the given XML string\r
- */\r
- DOMParser.prototype.parseFromString = function(sXml, contentType){\r
- if(contentType.toLowerCase() != "application/xml"){\r
- throw "Cannot handle content type: \"" + contentType + "\"";\r
- };\r
- var xmlhttp = new XMLHttpRequest();\r
- xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);\r
- xmlhttp.send(null);\r
- return xmlhttp.responseXML;\r
- };\r
- }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){\r
- DOMParser.prototype.parseFromString = function(sXml, contentType){\r
- var doc = Sarissa.getDomDocument();\r
- doc.loadXML(sXml);\r
- return doc;\r
- };\r
- };\r
-};\r
-\r
-if(window.XMLHttpRequest){\r
- Sarissa.IS_ENABLED_XMLHTTP = true;\r
-}\r
-else if(_SARISSA_IS_IE){\r
- /**\r
- * Emulate XMLHttpRequest\r
- * @constructor\r
- */\r
- XMLHttpRequest = function() {\r
- return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);\r
- };\r
- Sarissa.IS_ENABLED_XMLHTTP = true;\r
-};\r
-\r
-if(!window.document.importNode && _SARISSA_IS_IE){\r
- try{\r
- /**\r
- * Implements importNode for the current window document in IE using innerHTML.\r
- * Testing showed that DOM was multiple times slower than innerHTML for this,\r
- * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)\r
- * please gimme a call.\r
- * @param oNode the Node to import\r
- * @param bChildren whether to include the children of oNode\r
- * @returns the imported node for further use\r
- */\r
- window.document.importNode = function(oNode, bChildren){\r
- var importNode = document.createElement("div");\r
- if(bChildren)\r
- importNode.innerHTML = Sarissa.serialize(oNode);\r
- else\r
- importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));\r
- return importNode.firstChild;\r
- };\r
- }catch(e){};\r
-};\r
-if(!Sarissa.getParseErrorText){\r
- /**\r
- * <p>Returns a human readable description of the parsing error. Usefull\r
- * for debugging. Tip: append the returned error string in a <pre>\r
- * element if you want to render it.</p>\r
- * <p>Many thanks to Christian Stocker for the initial patch.</p>\r
- * @argument oDoc The target DOM document\r
- * @returns The parsing error description of the target Document in\r
- * human readable form (preformated text)\r
- */\r
- Sarissa.getParseErrorText = function (oDoc){\r
- var parseErrorText = Sarissa.PARSED_OK;\r
- if(oDoc && oDoc.parseError && oDoc.parseError != 0){\r
- /*moz*/\r
- if(oDoc.documentElement.tagName == "parsererror"){\r
- parseErrorText = oDoc.documentElement.firstChild.data;\r
- parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;\r
- }/*konq*/\r
- else{\r
- parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";\r
- parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";\r
- parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/\r
- };\r
- };\r
- return parseErrorText;\r
- };\r
-};\r
-Sarissa.getText = function(oNode, deep){\r
- var s = "";\r
- var nodes = oNode.childNodes;\r
- for(var i=0; i < nodes.length; i++){\r
- var node = nodes[i];\r
- var nodeType = node.nodeType;\r
- if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){\r
- s += node.data;\r
- }else if(deep == true\r
- && (nodeType == Node.ELEMENT_NODE\r
- || nodeType == Node.DOCUMENT_NODE\r
- || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){\r
- s += Sarissa.getText(node, true);\r
- };\r
- };\r
- return s;\r
-};\r
-if(window.XMLSerializer){\r
- /**\r
- * <p>Factory method to obtain the serialization of a DOM Node</p>\r
- * @returns the serialized Node as an XML string\r
- */\r
- Sarissa.serialize = function(oDoc){\r
- var s = null;\r
- if(oDoc){\r
- s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);\r
- };\r
- return s;\r
- };\r
-}else{\r
- if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){\r
- // see non-IE version\r
- Sarissa.serialize = function(oDoc) {\r
- var s = null;\r
- if(oDoc){\r
- s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;\r
- };\r
- return s;\r
- };\r
- /**\r
- * Utility class to serialize DOM Node objects to XML strings\r
- * @constructor\r
- */\r
- XMLSerializer = function(){};\r
- /**\r
- * Serialize the given DOM Node to an XML string\r
- * @param oNode the DOM Node to serialize\r
- */\r
- XMLSerializer.prototype.serializeToString = function(oNode) {\r
- return oNode.xml;\r
- };\r
- };\r
-};\r
-\r
-/**\r
- * strips tags from a markup string\r
- */\r
-Sarissa.stripTags = function (s) {\r
- return s.replace(/<[^>]+>/g,"");\r
-};\r
-/**\r
- * <p>Deletes all child nodes of the given node</p>\r
- * @argument oNode the Node to empty\r
- */\r
-Sarissa.clearChildNodes = function(oNode) {\r
- // need to check for firstChild due to opera 8 bug with hasChildNodes\r
- while(oNode.firstChild){\r
- oNode.removeChild(oNode.firstChild);\r
- };\r
-};\r
-/**\r
- * <p> Copies the childNodes of nodeFrom to nodeTo</p>\r
- * <p> <b>Note:</b> The second object's original content is deleted before \r
- * the copy operation, unless you supply a true third parameter</p>\r
- * @argument nodeFrom the Node to copy the childNodes from\r
- * @argument nodeTo the Node to copy the childNodes to\r
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false\r
- */\r
-Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {\r
- if((!nodeFrom) || (!nodeTo)){\r
- throw "Both source and destination nodes must be provided";\r
- };\r
- if(!bPreserveExisting){\r
- Sarissa.clearChildNodes(nodeTo);\r
- };\r
- var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;\r
- var nodes = nodeFrom.childNodes;\r
- if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {\r
- for(var i=0;i < nodes.length;i++) {\r
- nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));\r
- };\r
- }\r
- else{\r
- for(var i=0;i < nodes.length;i++) {\r
- nodeTo.appendChild(nodes[i].cloneNode(true));\r
- };\r
- };\r
-};\r
-\r
-/**\r
- * <p> Moves the childNodes of nodeFrom to nodeTo</p>\r
- * <p> <b>Note:</b> The second object's original content is deleted before \r
- * the move operation, unless you supply a true third parameter</p>\r
- * @argument nodeFrom the Node to copy the childNodes from\r
- * @argument nodeTo the Node to copy the childNodes to\r
- * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is\r
- */ \r
-Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {\r
- if((!nodeFrom) || (!nodeTo)){\r
- throw "Both source and destination nodes must be provided";\r
- };\r
- if(!bPreserveExisting){\r
- Sarissa.clearChildNodes(nodeTo);\r
- };\r
- var nodes = nodeFrom.childNodes;\r
- // if within the same doc, just move, else copy and delete\r
- if(nodeFrom.ownerDocument == nodeTo.ownerDocument){\r
- while(nodeFrom.firstChild){\r
- nodeTo.appendChild(nodeFrom.firstChild);\r
- };\r
- }else{\r
- var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;\r
- if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {\r
- for(var i=0;i < nodes.length;i++) {\r
- nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));\r
- };\r
- }else{\r
- for(var i=0;i < nodes.length;i++) {\r
- nodeTo.appendChild(nodes[i].cloneNode(true));\r
- };\r
- };\r
- Sarissa.clearChildNodes(nodeFrom);\r
- };\r
-};\r
-\r
-/** \r
- * <p>Serialize any object to an XML string. All properties are serialized using the property name\r
- * as the XML element name. Array elements are rendered as <code>array-item</code> elements, \r
- * using their index/key as the value of the <code>key</code> attribute.</p>\r
- * @argument anyObject the object to serialize\r
- * @argument objectName a name for that object\r
- * @return the XML serializationj of the given object as a string\r
- */\r
-Sarissa.xmlize = function(anyObject, objectName, indentSpace){\r
- indentSpace = indentSpace?indentSpace:'';\r
- var s = indentSpace + '<' + objectName + '>';\r
- var isLeaf = false;\r
- if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String \r
- || anyObject instanceof Boolean || anyObject instanceof Date){\r
- s += Sarissa.escape(""+anyObject);\r
- isLeaf = true;\r
- }else{\r
- s += "\n";\r
- var itemKey = '';\r
- var isArrayItem = anyObject instanceof Array;\r
- for(var name in anyObject){\r
- s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " ");\r
- };\r
- s += indentSpace;\r
- };\r
- return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");\r
-};\r
-\r
-/** \r
- * Escape the given string chacters that correspond to the five predefined XML entities\r
- * @param sXml the string to escape\r
- */\r
-Sarissa.escape = function(sXml){\r
- return sXml.replace(/&/g, "&")\r
- .replace(/</g, "<")\r
- .replace(/>/g, ">")\r
- .replace(/"/g, """)\r
- .replace(/'/g, "'");\r
-};\r
-\r
-/** \r
- * Unescape the given string. This turns the occurences of the predefined XML \r
- * entities to become the characters they represent correspond to the five predefined XML entities\r
- * @param sXml the string to unescape\r
- */\r
-Sarissa.unescape = function(sXml){\r
- return sXml.replace(/'/g,"'")\r
- .replace(/"/g,"\"")\r
- .replace(/>/g,">")\r
- .replace(/</g,"<")\r
- .replace(/&/g,"&");\r
-};\r
+
+/**
+ * ====================================================================
+ * About
+ * ====================================================================
+ * Sarissa is an ECMAScript library acting as a cross-browser wrapper for native XML APIs.
+ * The library supports Gecko based browsers like Mozilla and Firefox,
+ * Internet Explorer (5.5+ with MSXML3.0+), Konqueror, Safari and a little of Opera
+ * @version 0.9.6.1
+ * @author: Manos Batsis, mailto: mbatsis at users full stop sourceforge full stop net
+ * ====================================================================
+ * Licence
+ * ====================================================================
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 or
+ * the GNU Lesser General Public License version 2.1 as published by
+ * the Free Software Foundation (your choice between the two).
+ *
+ * This program 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 or GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * or GNU Lesser General Public License along with this program; if not,
+ * write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * or visit http://www.gnu.org
+ *
+ */
+/**
+ * <p>Sarissa is a utility class. Provides "static" methods for DOMDocument and
+ * XMLHTTP objects, DOM Node serializatrion to XML strings and other goodies.</p>
+ * @constructor
+ */
+function Sarissa(){};
+/** @private */
+Sarissa.PARSED_OK = "Document contains no parsing errors";
+/**
+ * Tells you whether transformNode and transformNodeToObject are available. This functionality
+ * is contained in sarissa_ieemu_xslt.js and is deprecated. If you want to control XSLT transformations
+ * use the XSLTProcessor
+ * @deprecated
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_TRANSFORM_NODE = false;
+/**
+ * tells you whether XMLHttpRequest (or equivalent) is available
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_XMLHTTP = false;
+/**
+ * tells you whether selectNodes/selectSingleNode is available
+ * @type boolean
+ */
+Sarissa.IS_ENABLED_SELECT_NODES = false;
+var _sarissa_iNsCounter = 0;
+var _SARISSA_IEPREFIX4XSLPARAM = "";
+var _SARISSA_HAS_DOM_IMPLEMENTATION = document.implementation && true;
+var _SARISSA_HAS_DOM_CREATE_DOCUMENT = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.createDocument;
+var _SARISSA_HAS_DOM_FEATURE = _SARISSA_HAS_DOM_IMPLEMENTATION && document.implementation.hasFeature;
+var _SARISSA_IS_MOZ = _SARISSA_HAS_DOM_CREATE_DOCUMENT && _SARISSA_HAS_DOM_FEATURE;
+var _SARISSA_IS_SAFARI = (navigator.userAgent && navigator.vendor && (navigator.userAgent.toLowerCase().indexOf("applewebkit") != -1 || navigator.vendor.indexOf("Apple") != -1));
+var _SARISSA_IS_IE = document.all && window.ActiveXObject && navigator.userAgent.toLowerCase().indexOf("msie") > -1 && navigator.userAgent.toLowerCase().indexOf("opera") == -1;
+if(!window.Node || !window.Node.ELEMENT_NODE){
+ var Node = {ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12};
+};
+
+// IE initialization
+if(_SARISSA_IS_IE){
+ // for XSLT parameter names, prefix needed by IE
+ _SARISSA_IEPREFIX4XSLPARAM = "xsl:";
+ // used to store the most recent ProgID available out of the above
+ var _SARISSA_DOM_PROGID = "";
+ var _SARISSA_XMLHTTP_PROGID = "";
+ /**
+ * Called when the Sarissa_xx.js file is parsed, to pick most recent
+ * ProgIDs for IE, then gets destroyed.
+ * @param idList an array of MSXML PROGIDs from which the most recent will be picked for a given object
+ * @param enabledList an array of arrays where each array has two items; the index of the PROGID for which a certain feature is enabled
+ */
+ pickRecentProgID = function (idList, enabledList){
+ // found progID flag
+ var bFound = false;
+ for(var i=0; i < idList.length && !bFound; i++){
+ try{
+ var oDoc = new ActiveXObject(idList[i]);
+ o2Store = idList[i];
+ bFound = true;
+ for(var j=0;j<enabledList.length;j++)
+ if(i <= enabledList[j][1])
+ Sarissa["IS_ENABLED_"+enabledList[j][0]] = true;
+ }catch (objException){
+ // trap; try next progID
+ };
+ };
+ if (!bFound)
+ throw "Could not retreive a valid progID of Class: " + idList[idList.length-1]+". (original exception: "+e+")";
+ idList = null;
+ return o2Store;
+ };
+ // pick best available MSXML progIDs
+ _SARISSA_DOM_PROGID = pickRecentProgID(["Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"], [["SELECT_NODES", 2],["TRANSFORM_NODE", 2]]);
+ _SARISSA_XMLHTTP_PROGID = pickRecentProgID(["Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"], [["XMLHTTP", 4]]);
+ _SARISSA_THREADEDDOM_PROGID = pickRecentProgID(["Msxml2.FreeThreadedDOMDocument.5.0", "MSXML2.FreeThreadedDOMDocument.4.0", "MSXML2.FreeThreadedDOMDocument.3.0"]);
+ _SARISSA_XSLTEMPLATE_PROGID = pickRecentProgID(["Msxml2.XSLTemplate.5.0", "Msxml2.XSLTemplate.4.0", "MSXML2.XSLTemplate.3.0"], [["XSLTPROC", 2]]);
+ // we dont need this anymore
+ pickRecentProgID = null;
+ //============================================
+ // Factory methods (IE)
+ //============================================
+ // see non-IE version
+ Sarissa.getDomDocument = function(sUri, sName){
+ var oDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
+ // if a root tag name was provided, we need to load it in the DOM
+ // object
+ if (sName){
+ // if needed, create an artifical namespace prefix the way Moz
+ // does
+ if (sUri){
+ oDoc.loadXML("<a" + _sarissa_iNsCounter + ":" + sName + " xmlns:a" + _sarissa_iNsCounter + "=\"" + sUri + "\" />");
+ // don't use the same prefix again
+ ++_sarissa_iNsCounter;
+ }
+ else
+ oDoc.loadXML("<" + sName + "/>");
+ };
+ return oDoc;
+ };
+ // see non-IE version
+ Sarissa.getParseErrorText = function (oDoc) {
+ var parseErrorText = Sarissa.PARSED_OK;
+ if(oDoc.parseError != 0){
+ parseErrorText = "XML Parsing Error: " + oDoc.parseError.reason +
+ "\nLocation: " + oDoc.parseError.url +
+ "\nLine Number " + oDoc.parseError.line + ", Column " +
+ oDoc.parseError.linepos +
+ ":\n" + oDoc.parseError.srcText +
+ "\n";
+ for(var i = 0; i < oDoc.parseError.linepos;i++){
+ parseErrorText += "-";
+ };
+ parseErrorText += "^\n";
+ };
+ return parseErrorText;
+ };
+ // see non-IE version
+ Sarissa.setXpathNamespaces = function(oDoc, sNsSet) {
+ oDoc.setProperty("SelectionLanguage", "XPath");
+ oDoc.setProperty("SelectionNamespaces", sNsSet);
+ };
+ /**
+ * Basic implementation of Mozilla's XSLTProcessor for IE.
+ * Reuses the same XSLT stylesheet for multiple transforms
+ * @constructor
+ */
+ XSLTProcessor = function(){
+ this.template = new ActiveXObject(_SARISSA_XSLTEMPLATE_PROGID);
+ this.processor = null;
+ };
+ /**
+ * Impoprts the given XSLT DOM and compiles it to a reusable transform
+ * @argument xslDoc The XSLT DOMDocument to import
+ */
+ XSLTProcessor.prototype.importStylesheet = function(xslDoc){
+ // convert stylesheet to free threaded
+ var converted = new ActiveXObject(_SARISSA_THREADEDDOM_PROGID);
+ converted.loadXML(xslDoc.xml);
+ this.template.stylesheet = converted;
+ this.processor = this.template.createProcessor();
+ // (re)set default param values
+ this.paramsSet = new Array();
+ };
+ /**
+ * Transform the given XML DOM
+ * @argument sourceDoc The XML DOMDocument to transform
+ * @return The transformation result as a DOM Document
+ */
+ XSLTProcessor.prototype.transformToDocument = function(sourceDoc){
+ this.processor.input = sourceDoc;
+ var outDoc = new ActiveXObject(_SARISSA_DOM_PROGID);
+ this.processor.output = outDoc;
+ this.processor.transform();
+ return outDoc;
+ };
+ /**
+ * Set global XSLT parameter of the imported stylesheet
+ * @argument nsURI The parameter namespace URI
+ * @argument name The parameter base name
+ * @argument value The new parameter value
+ */
+ XSLTProcessor.prototype.setParameter = function(nsURI, name, value){
+ /* nsURI is optional but cannot be null */
+ if(nsURI){
+ this.processor.addParameter(name, value, nsURI);
+ }else{
+ this.processor.addParameter(name, value);
+ };
+ /* update updated params for getParameter */
+ if(!this.paramsSet[""+nsURI]){
+ this.paramsSet[""+nsURI] = new Array();
+ };
+ this.paramsSet[""+nsURI][name] = value;
+ };
+ /**
+ * Gets a parameter if previously set by setParameter. Returns null
+ * otherwise
+ * @argument name The parameter base name
+ * @argument value The new parameter value
+ * @return The parameter value if reviously set by setParameter, null otherwise
+ */
+ XSLTProcessor.prototype.getParameter = function(nsURI, name){
+ nsURI = nsURI || "";
+ if(nsURI in this.paramsSet && name in this.paramsSet[nsURI]){
+ return this.paramsSet[nsURI][name];
+ }else{
+ return null;
+ };
+ };
+}
+else{ /* end IE initialization, try to deal with real browsers now ;-) */
+ if(_SARISSA_HAS_DOM_CREATE_DOCUMENT){
+ /**
+ * <p>Ensures the document was loaded correctly, otherwise sets the
+ * parseError to -1 to indicate something went wrong. Internal use</p>
+ * @private
+ */
+ Sarissa.__handleLoad__ = function(oDoc){
+ if (!oDoc.documentElement || oDoc.documentElement.tagName == "parsererror")
+ oDoc.parseError = -1;
+ Sarissa.__setReadyState__(oDoc, 4);
+ };
+ /**
+ * <p>Attached by an event handler to the load event. Internal use.</p>
+ * @private
+ */
+ _sarissa_XMLDocument_onload = function(){
+ Sarissa.__handleLoad__(this);
+ };
+ /**
+ * <p>Sets the readyState property of the given DOM Document object.
+ * Internal use.</p>
+ * @private
+ * @argument oDoc the DOM Document object to fire the
+ * readystatechange event
+ * @argument iReadyState the number to change the readystate property to
+ */
+ Sarissa.__setReadyState__ = function(oDoc, iReadyState){
+ oDoc.readyState = iReadyState;
+ if (oDoc.onreadystatechange != null && typeof oDoc.onreadystatechange == "function")
+ oDoc.onreadystatechange();
+ };
+ Sarissa.getDomDocument = function(sUri, sName){
+ var oDoc = document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
+ oDoc.addEventListener("load", _sarissa_XMLDocument_onload, false);
+ return oDoc;
+ };
+ if(window.XMLDocument){
+ /**
+ * <p>Emulate IE's onreadystatechange attribute</p>
+ */
+ XMLDocument.prototype.onreadystatechange = null;
+ /**
+ * <p>Emulates IE's readyState property, which always gives an integer from 0 to 4:</p>
+ * <ul><li>1 == LOADING,</li>
+ * <li>2 == LOADED,</li>
+ * <li>3 == INTERACTIVE,</li>
+ * <li>4 == COMPLETED</li></ul>
+ */
+ XMLDocument.prototype.readyState = 0;
+ /**
+ * <p>Emulate IE's parseError attribute</p>
+ */
+ XMLDocument.prototype.parseError = 0;
+
+ // NOTE: setting async to false will only work with documents
+ // called over HTTP (meaning a server), not the local file system,
+ // unless you are using Moz 1.4+.
+ // BTW the try>catch block is for 1.4; I haven't found a way to check if
+ // the property is implemented without
+ // causing an error and I dont want to use user agent stuff for that...
+ var _SARISSA_SYNC_NON_IMPLEMENTED = false;// ("async" in XMLDocument.prototype) ? false: true;
+ /**
+ * <p>Keeps a handle to the original load() method. Internal use and only
+ * if Mozilla version is lower than 1.4</p>
+ * @private
+ */
+ XMLDocument.prototype._sarissa_load = XMLDocument.prototype.load;
+
+ /**
+ * <p>Overrides the original load method to provide synchronous loading for
+ * Mozilla versions prior to 1.4, using an XMLHttpRequest object (if
+ * async is set to false)</p>
+ * @returns the DOM Object as it was before the load() call (may be empty)
+ */
+ XMLDocument.prototype.load = function(sURI) {
+ var oDoc = document.implementation.createDocument("", "", null);
+ Sarissa.copyChildNodes(this, oDoc);
+ this.parseError = 0;
+ Sarissa.__setReadyState__(this, 1);
+ try {
+ if(this.async == false && _SARISSA_SYNC_NON_IMPLEMENTED) {
+ var tmp = new XMLHttpRequest();
+ tmp.open("GET", sURI, false);
+ tmp.send(null);
+ Sarissa.__setReadyState__(this, 2);
+ Sarissa.copyChildNodes(tmp.responseXML, this);
+ Sarissa.__setReadyState__(this, 3);
+ }
+ else {
+ this._sarissa_load(sURI);
+ };
+ }
+ catch (objException) {
+ this.parseError = -1;
+ }
+ finally {
+ if(this.async == false){
+ Sarissa.__handleLoad__(this);
+ };
+ };
+ return oDoc;
+ };
+
+
+ }//if(window.XMLDocument)
+ else if(document.implementation && document.implementation.hasFeature && document.implementation.hasFeature('LS', '3.0')){
+ Document.prototype.async = true;
+ Document.prototype.onreadystatechange = null;
+ Document.prototype.parseError = 0;
+ Document.prototype.load = function(sURI) {
+ var parser = document.implementation.createLSParser(this.async ? document.implementation.MODE_ASYNCHRONOUS : document.implementation.MODE_SYNCHRONOUS, null);
+ if(this.async){
+ var self = this;
+ parser.addEventListener("load",
+ function(e) {
+ self.readyState = 4;
+ Sarissa.copyChildNodes(e.newDocument, self.documentElement, false);
+ self.onreadystatechange.call();
+ },
+ false);
+ };
+ try {
+ var oDoc = parser.parseURI(sURI);
+ }
+ catch(e){
+ this.parseError = -1;
+ };
+ if(!this.async)
+ Sarissa.copyChildNodes(oDoc, this.documentElement, false);
+ return oDoc;
+ };
+ /**
+ * <p>Factory method to obtain a new DOM Document object</p>
+ * @argument sUri the namespace of the root node (if any)
+ * @argument sUri the local name of the root node (if any)
+ * @returns a new DOM Document
+ */
+ Sarissa.getDomDocument = function(sUri, sName){
+ return document.implementation.createDocument(sUri?sUri:"", sName?sName:"", null);
+ };
+ };
+ };//if(_SARISSA_HAS_DOM_CREATE_DOCUMENT)
+};
+//==========================================
+// Common stuff
+//==========================================
+if(!window.DOMParser){
+ /*
+ * DOMParser is a utility class, used to construct DOMDocuments from XML strings
+ * @constructor
+ */
+ DOMParser = function() {
+ };
+ if(_SARISSA_IS_SAFARI){
+ /**
+ * Construct a new DOM Document from the given XMLstring
+ * @param sXml the given XML string
+ * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml).
+ * @return a new DOM Document from the given XML string
+ */
+ DOMParser.prototype.parseFromString = function(sXml, contentType){
+ if(contentType.toLowerCase() != "application/xml"){
+ throw "Cannot handle content type: \"" + contentType + "\"";
+ };
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(str), false);
+ xmlhttp.send(null);
+ return xmlhttp.responseXML;
+ };
+ }else if(Sarissa.getDomDocument && Sarissa.getDomDocument() && "loadXML" in Sarissa.getDomDocument()){
+ DOMParser.prototype.parseFromString = function(sXml, contentType){
+ var doc = Sarissa.getDomDocument();
+ doc.loadXML(sXml);
+ return doc;
+ };
+ };
+};
+
+if(window.XMLHttpRequest){
+ Sarissa.IS_ENABLED_XMLHTTP = true;
+}
+else if(_SARISSA_IS_IE){
+ /**
+ * Emulate XMLHttpRequest
+ * @constructor
+ */
+ XMLHttpRequest = function() {
+ return new ActiveXObject(_SARISSA_XMLHTTP_PROGID);
+ };
+ Sarissa.IS_ENABLED_XMLHTTP = true;
+};
+
+if(!window.document.importNode && _SARISSA_IS_IE){
+ try{
+ /**
+ * Implements importNode for the current window document in IE using innerHTML.
+ * Testing showed that DOM was multiple times slower than innerHTML for this,
+ * sorry folks. If you encounter trouble (who knows what IE does behind innerHTML)
+ * please gimme a call.
+ * @param oNode the Node to import
+ * @param bChildren whether to include the children of oNode
+ * @returns the imported node for further use
+ */
+ window.document.importNode = function(oNode, bChildren){
+ var importNode = document.createElement("div");
+ if(bChildren)
+ importNode.innerHTML = Sarissa.serialize(oNode);
+ else
+ importNode.innerHTML = Sarissa.serialize(oNode.cloneNode(false));
+ return importNode.firstChild;
+ };
+ }catch(e){};
+};
+if(!Sarissa.getParseErrorText){
+ /**
+ * <p>Returns a human readable description of the parsing error. Usefull
+ * for debugging. Tip: append the returned error string in a <pre>
+ * element if you want to render it.</p>
+ * <p>Many thanks to Christian Stocker for the initial patch.</p>
+ * @argument oDoc The target DOM document
+ * @returns The parsing error description of the target Document in
+ * human readable form (preformated text)
+ */
+ Sarissa.getParseErrorText = function (oDoc){
+ var parseErrorText = Sarissa.PARSED_OK;
+ if(oDoc && oDoc.parseError && oDoc.parseError != 0){
+ /*moz*/
+ if(oDoc.documentElement.tagName == "parsererror"){
+ parseErrorText = oDoc.documentElement.firstChild.data;
+ parseErrorText += "\n" + oDoc.documentElement.firstChild.nextSibling.firstChild.data;
+ }/*konq*/
+ else{
+ parseErrorText = Sarissa.getText(oDoc.documentElement);/*.getElementsByTagName("h1")[0], false) + "\n";
+ parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("body")[0], false) + "\n";
+ parseErrorText += Sarissa.getText(oDoc.documentElement.getElementsByTagName("pre")[0], false);*/
+ };
+ };
+ return parseErrorText;
+ };
+};
+Sarissa.getText = function(oNode, deep){
+ var s = "";
+ var nodes = oNode.childNodes;
+ for(var i=0; i < nodes.length; i++){
+ var node = nodes[i];
+ var nodeType = node.nodeType;
+ if(nodeType == Node.TEXT_NODE || nodeType == Node.CDATA_SECTION_NODE){
+ s += node.data;
+ }else if(deep == true
+ && (nodeType == Node.ELEMENT_NODE
+ || nodeType == Node.DOCUMENT_NODE
+ || nodeType == Node.DOCUMENT_FRAGMENT_NODE)){
+ s += Sarissa.getText(node, true);
+ };
+ };
+ return s;
+};
+if(window.XMLSerializer){
+ /**
+ * <p>Factory method to obtain the serialization of a DOM Node</p>
+ * @returns the serialized Node as an XML string
+ */
+ Sarissa.serialize = function(oDoc){
+ var s = null;
+ if(oDoc){
+ s = oDoc.innerHTML?oDoc.innerHTML:(new XMLSerializer()).serializeToString(oDoc);
+ };
+ return s;
+ };
+}else{
+ if(Sarissa.getDomDocument && (Sarissa.getDomDocument("","foo", null)).xml){
+ // see non-IE version
+ Sarissa.serialize = function(oDoc) {
+ var s = null;
+ if(oDoc){
+ s = oDoc.innerHTML?oDoc.innerHTML:oDoc.xml;
+ };
+ return s;
+ };
+ /**
+ * Utility class to serialize DOM Node objects to XML strings
+ * @constructor
+ */
+ XMLSerializer = function(){};
+ /**
+ * Serialize the given DOM Node to an XML string
+ * @param oNode the DOM Node to serialize
+ */
+ XMLSerializer.prototype.serializeToString = function(oNode) {
+ return oNode.xml;
+ };
+ };
+};
+
+/**
+ * strips tags from a markup string
+ */
+Sarissa.stripTags = function (s) {
+ return s.replace(/<[^>]+>/g,"");
+};
+/**
+ * <p>Deletes all child nodes of the given node</p>
+ * @argument oNode the Node to empty
+ */
+Sarissa.clearChildNodes = function(oNode) {
+ // need to check for firstChild due to opera 8 bug with hasChildNodes
+ while(oNode.firstChild){
+ oNode.removeChild(oNode.firstChild);
+ };
+};
+/**
+ * <p> Copies the childNodes of nodeFrom to nodeTo</p>
+ * <p> <b>Note:</b> The second object's original content is deleted before
+ * the copy operation, unless you supply a true third parameter</p>
+ * @argument nodeFrom the Node to copy the childNodes from
+ * @argument nodeTo the Node to copy the childNodes to
+ * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is false
+ */
+Sarissa.copyChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
+ if((!nodeFrom) || (!nodeTo)){
+ throw "Both source and destination nodes must be provided";
+ };
+ if(!bPreserveExisting){
+ Sarissa.clearChildNodes(nodeTo);
+ };
+ var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
+ var nodes = nodeFrom.childNodes;
+ if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
+ for(var i=0;i < nodes.length;i++) {
+ nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
+ };
+ }
+ else{
+ for(var i=0;i < nodes.length;i++) {
+ nodeTo.appendChild(nodes[i].cloneNode(true));
+ };
+ };
+};
+
+/**
+ * <p> Moves the childNodes of nodeFrom to nodeTo</p>
+ * <p> <b>Note:</b> The second object's original content is deleted before
+ * the move operation, unless you supply a true third parameter</p>
+ * @argument nodeFrom the Node to copy the childNodes from
+ * @argument nodeTo the Node to copy the childNodes to
+ * @argument bPreserveExisting whether to preserve the original content of nodeTo, default is
+ */
+Sarissa.moveChildNodes = function(nodeFrom, nodeTo, bPreserveExisting) {
+ if((!nodeFrom) || (!nodeTo)){
+ throw "Both source and destination nodes must be provided";
+ };
+ if(!bPreserveExisting){
+ Sarissa.clearChildNodes(nodeTo);
+ };
+ var nodes = nodeFrom.childNodes;
+ // if within the same doc, just move, else copy and delete
+ if(nodeFrom.ownerDocument == nodeTo.ownerDocument){
+ while(nodeFrom.firstChild){
+ nodeTo.appendChild(nodeFrom.firstChild);
+ };
+ }else{
+ var ownerDoc = nodeTo.nodeType == Node.DOCUMENT_NODE ? nodeTo : nodeTo.ownerDocument;
+ if(ownerDoc.importNode && (!_SARISSA_IS_IE)) {
+ for(var i=0;i < nodes.length;i++) {
+ nodeTo.appendChild(ownerDoc.importNode(nodes[i], true));
+ };
+ }else{
+ for(var i=0;i < nodes.length;i++) {
+ nodeTo.appendChild(nodes[i].cloneNode(true));
+ };
+ };
+ Sarissa.clearChildNodes(nodeFrom);
+ };
+};
+
+/**
+ * <p>Serialize any object to an XML string. All properties are serialized using the property name
+ * as the XML element name. Array elements are rendered as <code>array-item</code> elements,
+ * using their index/key as the value of the <code>key</code> attribute.</p>
+ * @argument anyObject the object to serialize
+ * @argument objectName a name for that object
+ * @return the XML serializationj of the given object as a string
+ */
+Sarissa.xmlize = function(anyObject, objectName, indentSpace){
+ indentSpace = indentSpace?indentSpace:'';
+ var s = indentSpace + '<' + objectName + '>';
+ var isLeaf = false;
+ if(!(anyObject instanceof Object) || anyObject instanceof Number || anyObject instanceof String
+ || anyObject instanceof Boolean || anyObject instanceof Date){
+ s += Sarissa.escape(""+anyObject);
+ isLeaf = true;
+ }else{
+ s += "\n";
+ var itemKey = '';
+ var isArrayItem = anyObject instanceof Array;
+ for(var name in anyObject){
+ s += Sarissa.xmlize(anyObject[name], (isArrayItem?"array-item key=\""+name+"\"":name), indentSpace + " ");
+ };
+ s += indentSpace;
+ };
+ return s += (objectName.indexOf(' ')!=-1?"</array-item>\n":"</" + objectName + ">\n");
+};
+
+/**
+ * Escape the given string chacters that correspond to the five predefined XML entities
+ * @param sXml the string to escape
+ */
+Sarissa.escape = function(sXml){
+ return sXml.replace(/&/g, "&")
+ .replace(/</g, "<")
+ .replace(/>/g, ">")
+ .replace(/"/g, """)
+ .replace(/'/g, "'");
+};
+
+/**
+ * Unescape the given string. This turns the occurences of the predefined XML
+ * entities to become the characters they represent correspond to the five predefined XML entities
+ * @param sXml the string to unescape
+ */
+Sarissa.unescape = function(sXml){
+ return sXml.replace(/'/g,"'")
+ .replace(/"/g,"\"")
+ .replace(/>/g,">")
+ .replace(/</g,"<")
+ .replace(/&/g,"&");
+};
//
\ No newline at end of file
-/* make some small fonts a little bigger */\r
-.logininfo, .helplink, .minicalendar *, .link, .footer {\r
- font-size: 9pt !important;\r
-}\r
+/* make some small fonts a little bigger */
+.logininfo, .helplink, .minicalendar *, .link, .footer {
+ font-size: 9pt !important;
+}