$temp->add(new admin_setting_configcheckbox('xmlstrictheaders', get_string('xmlstrictheaders', 'admin'), get_string('configxmlstrictheaders', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('debugsmtp', get_string('debugsmtp', 'admin'), get_string('configdebugsmtp', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('perfdebug', get_string('perfdebug', 'admin'), get_string('configperfdebug', 'admin'), '7', '15', '7'));
- $temp->add(new admin_setting_configcheckbox('debugstringids', get_string('debugstringids', 'admin'), get_string('configdebugstringids', 'admin'), 0));
+ $temp->add(new admin_setting_configcheckbox('debugstringids', get_string('debugstringids', 'admin'), get_string('debugstringids_desc', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('debugvalidators', get_string('debugvalidators', 'admin'), get_string('configdebugvalidators', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('debugpageinfo', get_string('debugpageinfo', 'admin'), get_string('configdebugpageinfo', 'admin'), 0));
$ADMIN->add('development', $temp);
foreach ($initials as $initial) {
$var = 'si'.$initial;
+ $othervar = $initial == 'first' ? 'silast' : 'sifirst';
+ $othervar = $$othervar != 'all' ? "&{$othervar}={$$othervar}" : '';
+
$pagingbar .= ' <div class="initialbar '.$initial.'initial">';
$pagingbar .= get_string($initial.'name').': ';
$pagingbar .= '<strong>'.get_string('all').'</strong> ';
}
else {
- $pagingbar .= '<a href="'.$link.'">'.get_string('all').'</a> ';
+ $pagingbar .= "<a href=\"{$link}{$othervar}\">".get_string('all').'</a> ';
}
foreach ($alphabet as $letter) {
$pagingbar .= '<strong>'.$letter.'</strong> ';
}
else {
- $pagingbar .= '<a href="'.$link.'&'.$var.'='.$letter.'">'.$letter.'</a> ';
+ $pagingbar .= "<a href=\"$link&$var={$letter}{$othervar}\">$letter</a> ";
}
}
$pagingbar .= '<div class="paging">';
$pagingbar .= get_string('page').': ';
+ $sistrings = array();
+ $sistrings[] = $sifirst != 'all' ? "sifirst={$sifirst}" : null;
+ $sistrings[] = $silast != 'all' ? "silast={$silast}" : null;
+ $sistring = !empty($sistrings) ? implode('&', $sistrings) : '';
+
// Display previous link
if ($start > 0) {
$pstart = max($start - COMPLETION_REPORT_PAGE, 0);
- $pagingbar .= '(<a class="previous" href="'.$link.$pstart.'">'.get_string('previous').'</a>) ';
+ $pagingbar .= "(<a class=\"previous\" href=\"{$link}{$pstart}{$sistring}\">".get_string('previous').'</a>) ';
}
// Create page links
$pagingbar .= ' '.$curpage.' ';
}
else {
- $pagingbar .= ' <a href="'.$link.$curstart.'">'.$curpage.'</a> ';
+ $pagingbar .= " <a href=\"{$link}{$curstart}{$sistring}\">$curpage</a> ";
}
$curstart += COMPLETION_REPORT_PAGE;
// Display next link
$nstart = $start + COMPLETION_REPORT_PAGE;
if ($nstart < $total) {
- $pagingbar .= ' (<a class="next" href="'.$link.$nstart.'">'.get_string('next').'</a>)';
+ $pagingbar .= " (<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)';
}
$pagingbar .= '</div>';
// User heading / sort option
print '<th scope="col" class="completion-sortchoice" style="clear: both;">';
+
+ $sistring = "&silast={$silast}&sifirst={$sifirst}";
+
if($firstnamesort) {
print
- get_string('firstname').' / <a href="./?course='.$course->id.'">'.
+ get_string('firstname')." / <a href=\"./?course={$course->id}{$sistring}\">".
get_string('lastname').'</a>';
} else {
- print '<a href="./?course='.$course->id.'&sort=firstname">'.
+ print "<a href=\"./?course={$course->id}&sort=firstname{$sistring}\">".
get_string('firstname').'</a> / '.
get_string('lastname');
}
foreach ($initials as $initial) {
$var = 'si'.$initial;
+ $othervar = $initial == 'first' ? 'silast' : 'sifirst';
+ $othervar = $$othervar != 'all' ? "&{$othervar}={$$othervar}" : '';
+
$pagingbar .= ' <div class="initialbar '.$initial.'initial">';
$pagingbar .= get_string($initial.'name').': ';
$pagingbar .= '<strong>'.get_string('all').'</strong> ';
}
else {
- $pagingbar .= '<a href="'.$link.'">'.get_string('all').'</a> ';
+ $pagingbar .= "<a href=\"{$link}{$othervar}\">".get_string('all').'</a> ';
}
foreach ($alphabet as $letter) {
$pagingbar .= '<strong>'.$letter.'</strong> ';
}
else {
- $pagingbar .= '<a href="'.$link.'&'.$var.'='.$letter.'">'.$letter.'</a> ';
+ $pagingbar .= "<a href=\"$link&$var={$letter}{$othervar}\">$letter</a> ";
}
}
$pagingbar .= '<div class="paging">';
$pagingbar .= get_string('page').': ';
+ $sistrings = array();
+ $sistrings[] = $sifirst != 'all' ? "sifirst={$sifirst}" : null;
+ $sistrings[] = $silast != 'all' ? "silast={$silast}" : null;
+ $sistring = !empty($sistrings) ? implode('&', $sistrings) : '';
+
// Display previous link
if ($start > 0) {
$pstart = max($start - COMPLETION_REPORT_PAGE, 0);
- $pagingbar .= '(<a class="previous" href="'.$link.$pstart.'">'.get_string('previous').'</a>) ';
+ $pagingbar .= "(<a class=\"previous\" href=\"{$link}{$pstart}{$sistring}\">".get_string('previous').'</a>) ';
}
// Create page links
$pagingbar .= ' '.$curpage.' ';
}
else {
- $pagingbar .= ' <a href="'.$link.$curstart.'">'.$curpage.'</a> ';
+ $pagingbar .= " <a href=\"{$link}{$curstart}{$sistring}\">$curpage</a> ";
}
$curstart += COMPLETION_REPORT_PAGE;
// Display next link
$nstart = $start + COMPLETION_REPORT_PAGE;
if ($nstart < $total) {
- $pagingbar .= ' (<a class="next" href="'.$link.$nstart.'">'.get_string('next').'</a>)';
+ $pagingbar .= " (<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)';
}
$pagingbar .= '</div>';
// User heading / sort option
print '<th scope="col" class="completion-sortchoice">';
+
+ $sistring = "&silast={$silast}&sifirst={$sifirst}";
+
if($firstnamesort) {
print
- get_string('firstname').' / <a href="./?course='.$course->id.'">'.
+ get_string('firstname')." / <a href=\"./?course={$course->id}{$sistring}\">".
get_string('lastname').'</a>';
} else {
- print '<a href="./?course='.$course->id.'&sort=firstname">'.
+ print "<a href=\"./?course={$course->id}&sort=firstname{$sistring}\">".
get_string('firstname').'</a> / '.
get_string('lastname');
}
$string['configdebugdisplay'] = 'Set to on, the error reporting will go to the HTML page. This is practical, but breaks XHTML, JS, cookies and HTTP headers in general. Set to off, it will send the output to your server logs, allowing better debugging. The PHP setting error_log controls which log this goes to.';
$string['configdebugpageinfo'] = 'Enable if you want page information printed in page footer.';
$string['configdebugsmtp'] = 'Enable verbose debug information during sending of email messages to SMTP server.';
-$string['configdebugstringids'] = 'This option is designed to help translators. It shows the language file and string id beside each string that is output. (Changing this setting will only take effect on the next page load.)';
$string['configdebugvalidators'] = 'Enable if you want to have links to external validator servers in page footer. You may need to create new user with username <em>w3cvalidator</em>, and enable guest access. These changes may allow unauthorized access to server, do not enable on production sites!';
$string['configdefaultallowedmodules'] = 'For the courses which fall into the above category, which modules do you want to allow by default <b>when the course is created</b>?';
$string['configdefaulthomepage'] = 'This determines the home page for logged in users';
$string['debugpageinfo'] = 'Show page information';
$string['debugsmtp'] = 'Debug email sending';
$string['debugstringids'] = 'Show origin of languages strings';
+$string['debugstringids_desc'] = 'This option is designed to help translators. When this option is enabled, if you add the parameter strings=1 to a request URL, it will show the language file and string id beside each string that is output.';
$string['debugvalidators'] = 'Show validator links';
$string['defaultallowedmodules'] = 'Default allowed modules';
$string['defaultcity'] = 'Default city';
$string['erroroccur'] = 'An error has occurred during this process';
$string['invalidarraysize'] = 'Incorrect size of arrays in params of {$a}';
$string['invalideventdata'] = 'Incorrect eventadata submitted: {$a}';
-$string['invalidparameter'] = 'Invalid parameter value detected, execution can not continue.';
-$string['invalidresponse'] = 'Invalid response value detected, execution can not continue.';
+$string['invalidparameter'] = 'Invalid parameter value detected';
+$string['invalidresponse'] = 'Invalid response value detected';
$string['missingconfigversion'] = 'Config table does not contain version, can not continue, sorry.';
$string['modulenotexist'] = '{$a} module doesn\'t exist';
$string['morethanonerecordinfetch'] = 'Found more than one record in fetch() !';
$string['errorcodes'] = 'Error message';
$string['errorcoursecontextnotvalid'] = 'You cannot execute functions in the course context (course id:{$a->courseid}). The context error message was: {$a->message}';
$string['errorinvalidparam'] = 'The param "{$a}" is invalid.';
-$string['errorinvalidparamsapi'] = 'Invalid external api parameter';
-$string['errorinvalidparamsdesc'] = 'Invalid external api description';
-$string['errorinvalidresponseapi'] = 'Invalid external api response';
-$string['errorinvalidresponsedesc'] = 'Invalid external api response description';
-$string['errormissingkey'] = 'Missing required key in single structure: {$a}';
$string['errornotemptydefaultparamarray'] = 'The web service description parameter named \'{$a}\' is an single or multiple structure. The default can only be empty array. Check web service description.';
-$string['erroronlyarray'] = 'Only arrays accepted.';
$string['erroroptionalparamarray'] = 'The web service description parameter named \'{$a}\' is an single or multiple structure. It can not be set as VALUE_OPTIONAL. Check web service description.';
-$string['errorresponsemissingkey'] = 'Error in response - Missing following required key in a single structure: {$a}';
-$string['errorscalartype'] = 'Scalar type expected, array or object received.';
-$string['errorunexpectedkey'] = 'Unexpected keys ({$a}) detected in parameter array.';
$string['execute'] = 'Execute';
$string['executewarnign'] = 'WARNING: If you press execute your database will be modified and changes can not be reverted automatically!';
$string['externalservice'] = 'External service';
//TODO: in order to let the administrator delete obsolete token, split this request in multiple request or use LEFT JOIN
//here retrieve token list (including linked users firstname/lastname and linked services name)
- $sql = "SELECT t.id, t.token, u.id AS userid, u.firstname, u.lastname, s.name, t.validuntil, s.id AS serviceid
+ $sql = "SELECT t.id, t.token, u.id AS userid, u.firstname, u.lastname, s.name, t.iprestriction, t.validuntil, s.id AS serviceid
FROM {external_tokens} t, {user} u, {external_services} s
WHERE t.creatorid=? AND t.tokentype = ? AND s.id = t.externalserviceid AND t.userid = u.id";
$tokens = $DB->get_records_sql($sql, array($USER->id, EXTERNAL_TOKEN_PERMANENT));
global $CFG;
$this->set_queue($langcode);
- $this->version = '2.1';
+ $this->version = '2.2';
if (!empty($CFG->langotherroot) and $CFG->langotherroot !== $CFG->dataroot . '/lang') {
debugging('The in-built language pack installer does not support alternative location ' .
public static function validate_parameters(external_description $description, $params) {
if ($description instanceof external_value) {
if (is_array($params) or is_object($params)) {
- throw new invalid_parameter_exception(get_string('errorscalartype', 'webservice'));
+ throw new invalid_parameter_exception('Scalar type expected, array or object received.');
}
if ($description->type == PARAM_BOOL) {
return (bool)$params;
}
}
- return validate_param($params, $description->type, $description->allownull, get_string('errorinvalidparamsapi', 'webservice'));
+ $debuginfo = 'Invalid external api parameter: the value is "' . $params .
+ '", the server was expecting "' . $description->type . '" type';
+ return validate_param($params, $description->type, $description->allownull, $debuginfo);
} else if ($description instanceof external_single_structure) {
if (!is_array($params)) {
- throw new invalid_parameter_exception(get_string('erroronlyarray', 'webservice'));
+ throw new invalid_parameter_exception('Only arrays accepted. The bad value is: \''
+ . print_r($params, true) . '\'');
}
$result = array();
foreach ($description->keys as $key=>$subdesc) {
if (!array_key_exists($key, $params)) {
if ($subdesc->required == VALUE_REQUIRED) {
- throw new invalid_parameter_exception(get_string('errormissingkey', 'webservice', $key));
+ throw new invalid_parameter_exception('Missing required key in single structure: '. $key);
}
if ($subdesc->required == VALUE_DEFAULT) {
try {
$result[$key] = self::validate_parameters($subdesc, $subdesc->default);
} catch (invalid_parameter_exception $e) {
- throw new webservice_parameter_exception('invalidextparam',$key);
+ //we are only interested by exceptions returned by validate_param() and validate_parameters()
+ //(in order to build the path to the faulty attribut)
+ throw new invalid_parameter_exception($key." => ".$e->getMessage() . ': ' .$e->debuginfo);
}
}
} else {
try {
$result[$key] = self::validate_parameters($subdesc, $params[$key]);
} catch (invalid_parameter_exception $e) {
- //it's ok to display debug info as here the information is useful for ws client/dev
- throw new webservice_parameter_exception('invalidextparam',$key." (".$e->debuginfo.")");
+ //we are only interested by exceptions returned by validate_param() and validate_parameters()
+ //(in order to build the path to the faulty attribut)
+ throw new invalid_parameter_exception($key." => ".$e->getMessage() . ': ' .$e->debuginfo);
}
}
unset($params[$key]);
}
if (!empty($params)) {
- //list all unexpected keys
- $keys = '';
- foreach($params as $key => $value) {
- $keys .= $key . ',';
- }
- throw new invalid_parameter_exception(get_string('errorunexpectedkey', 'webservice', $keys));
+ throw new invalid_parameter_exception('Unexpected keys (' . implode(', ', array_keys($params)) . ') detected in parameter array.');
}
return $result;
} else if ($description instanceof external_multiple_structure) {
if (!is_array($params)) {
- throw new invalid_parameter_exception(get_string('erroronlyarray', 'webservice'));
+ throw new invalid_parameter_exception('Only arrays accepted. The bad value is: \''
+ . print_r($params, true) . '\'');
}
$result = array();
foreach ($params as $param) {
return $result;
} else {
- throw new invalid_parameter_exception(get_string('errorinvalidparamsdesc', 'webservice'));
+ throw new invalid_parameter_exception('Invalid external api description');
}
}
public static function clean_returnvalue(external_description $description, $response) {
if ($description instanceof external_value) {
if (is_array($response) or is_object($response)) {
- throw new invalid_response_exception(get_string('errorscalartype', 'webservice'));
+ throw new invalid_response_exception('Scalar type expected, array or object received.');
}
if ($description->type == PARAM_BOOL) {
return (bool)$response;
}
}
- return validate_param($response, $description->type, $description->allownull, get_string('errorinvalidresponseapi', 'webservice'));
+ $debuginfo = 'Invalid external api response: the value is "' . $response .
+ '", the server was expecting "' . $description->type . '" type';
+ try {
+ return validate_param($response, $description->type, $description->allownull, $debuginfo);
+ } catch (invalid_parameter_exception $e) {
+ //proper exception name, to be recursively catched to build the path to the faulty attribut
+ throw new invalid_response_exception($e->debuginfo);
+ }
} else if ($description instanceof external_single_structure) {
if (!is_array($response)) {
- throw new invalid_response_exception(get_string('erroronlyarray', 'webservice'));
+ throw new invalid_response_exception('Only arrays accepted. The bad value is: \'' .
+ print_r($response, true) . '\'');
}
$result = array();
foreach ($description->keys as $key=>$subdesc) {
if (!array_key_exists($key, $response)) {
if ($subdesc->required == VALUE_REQUIRED) {
- throw new webservice_parameter_exception('errorresponsemissingkey', $key);
+ throw new invalid_response_exception('Error in response - Missing following required key in a single structure: ' . $key);
}
if ($subdesc instanceof external_value) {
if ($subdesc->required == VALUE_DEFAULT) {
try {
$result[$key] = self::clean_returnvalue($subdesc, $subdesc->default);
- } catch (Exception $e) {
- throw new webservice_parameter_exception('invalidextresponse',$key." (".$e->debuginfo.")");
+ } catch (invalid_response_exception $e) {
+ //build the path to the faulty attribut
+ throw new invalid_response_exception($key." => ".$e->getMessage() . ': ' . $e->debuginfo);
}
}
}
} else {
try {
$result[$key] = self::clean_returnvalue($subdesc, $response[$key]);
- } catch (Exception $e) {
- //it's ok to display debug info as here the information is useful for ws client/dev
- throw new webservice_parameter_exception('invalidextresponse',$key." (".$e->debuginfo.")");
+ } catch (invalid_response_exception $e) {
+ //build the path to the faulty attribut
+ throw new invalid_response_exception($key." => ".$e->getMessage() . ': ' . $e->debuginfo);
}
}
unset($response[$key]);
} else if ($description instanceof external_multiple_structure) {
if (!is_array($response)) {
- throw new invalid_response_exception(get_string('erroronlyarray', 'webservice'));
+ throw new invalid_response_exception('Only arrays accepted. The bad value is: \'' .
+ print_r($response, true) . '\'');
}
$result = array();
foreach ($response as $param) {
return $result;
} else {
- throw new invalid_response_exception(get_string('errorinvalidresponsedesc', 'webservice'));
+ throw new invalid_response_exception('Invalid external api response description');
}
}
}
}
+ if ($key === 'timecreated' or $key === 'timemodified') {
+ if (!is_number($value)) {
+ throw new file_exception('storedfileproblem', 'Invalid file '.$key);
+ }
+ if ($value < 0) {
+ //NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
+ $value = 0;
+ }
+ }
+
$newrecord->$key = $value;
}
try {
$newrecord->id = $DB->insert_record('files', $newrecord);
} catch (dml_exception $e) {
- $newrecord->id = false;
- }
-
- if (!$newrecord->id) {
throw new stored_file_creation_exception($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid,
- $newrecord->filepath, $newrecord->filename);
+ $newrecord->filepath, $newrecord->filename, $e->debuginfo);
}
$this->create_directory($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->userid);
}
$now = time();
+ if (isset($file_record->timecreated)) {
+ if (!is_number($file_record->timecreated)) {
+ throw new file_exception('storedfileproblem', 'Invalid file timecreated');
+ }
+ if ($file_record->timecreated < 0) {
+ //NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
+ $file_record->timecreated = 0;
+ }
+ } else {
+ $file_record->timecreated = $now;
+ }
+
+ if (isset($file_record->timemodified)) {
+ if (!is_number($file_record->timemodified)) {
+ throw new file_exception('storedfileproblem', 'Invalid file timemodified');
+ }
+ if ($file_record->timemodified < 0) {
+ //NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
+ $file_record->timemodified = 0;
+ }
+ } else {
+ $file_record->timemodified = $now;
+ }
$newrecord = new stdClass();
$newrecord->filepath = $file_record->filepath;
$newrecord->filename = $file_record->filename;
- $newrecord->timecreated = empty($file_record->timecreated) ? $now : $file_record->timecreated;
- $newrecord->timemodified = empty($file_record->timemodified) ? $now : $file_record->timemodified;
+ $newrecord->timecreated = $file_record->timecreated;
+ $newrecord->timemodified = $file_record->timemodified;
$newrecord->mimetype = empty($file_record->mimetype) ? mimeinfo('type', $file_record->filename) : $file_record->mimetype;
$newrecord->userid = empty($file_record->userid) ? null : $file_record->userid;
$newrecord->source = empty($file_record->source) ? null : $file_record->source;
try {
$newrecord->id = $DB->insert_record('files', $newrecord);
} catch (dml_exception $e) {
- $newrecord->id = false;
- }
-
- if (!$newrecord->id) {
if ($newfile) {
$this->deleted_file_cleanup($newrecord->contenthash);
}
throw new stored_file_creation_exception($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid,
- $newrecord->filepath, $newrecord->filename);
+ $newrecord->filepath, $newrecord->filename, $e->debuginfo);
}
$this->create_directory($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->userid);
}
$now = time();
+ if (isset($file_record->timecreated)) {
+ if (!is_number($file_record->timecreated)) {
+ throw new file_exception('storedfileproblem', 'Invalid file timecreated');
+ }
+ if ($file_record->timecreated < 0) {
+ //NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
+ $file_record->timecreated = 0;
+ }
+ } else {
+ $file_record->timecreated = $now;
+ }
+
+ if (isset($file_record->timemodified)) {
+ if (!is_number($file_record->timemodified)) {
+ throw new file_exception('storedfileproblem', 'Invalid file timemodified');
+ }
+ if ($file_record->timemodified < 0) {
+ //NOTE: unfortunately I make a mistake when creating the "files" table, we can not have negative numbers there, on the other hand no file should be older than 1970, right? (skodak)
+ $file_record->timemodified = 0;
+ }
+ } else {
+ $file_record->timemodified = $now;
+ }
$newrecord = new stdClass();
$newrecord->filepath = $file_record->filepath;
$newrecord->filename = $file_record->filename;
- $newrecord->timecreated = empty($file_record->timecreated) ? $now : $file_record->timecreated;
- $newrecord->timemodified = empty($file_record->timemodified) ? $now : $file_record->timemodified;
+ $newrecord->timecreated = $file_record->timecreated;
+ $newrecord->timemodified = $file_record->timemodified;
$newrecord->mimetype = empty($file_record->mimetype) ? mimeinfo('type', $file_record->filename) : $file_record->mimetype;
$newrecord->userid = empty($file_record->userid) ? null : $file_record->userid;
$newrecord->source = empty($file_record->source) ? null : $file_record->source;
try {
$newrecord->id = $DB->insert_record('files', $newrecord);
} catch (dml_exception $e) {
- $newrecord->id = false;
- }
-
- if (!$newrecord->id) {
if ($newfile) {
$this->deleted_file_cleanup($newrecord->contenthash);
}
throw new stored_file_creation_exception($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid,
- $newrecord->filepath, $newrecord->filename);
+ $newrecord->filepath, $newrecord->filename, $e->debuginfo);
}
$this->create_directory($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->userid);
* @return string The localized string.
*/
function get_string($identifier, $component = '', $a = NULL) {
+ global $CFG;
$identifier = clean_param($identifier, PARAM_STRINGID);
if (empty($identifier)) {
}
}
- return get_string_manager()->get_string($identifier, $component, $a);
+ $result = get_string_manager()->get_string($identifier, $component, $a);
+
+ // Debugging feature lets you display string identifier and component
+ if ($CFG->debugstringids && optional_param('strings', 0, PARAM_INT)) {
+ $result .= ' {' . $identifier . '/' . $component . '}';
+ }
+ return $result;
}
/**
/**
* Web service parameter exception class
- *
+ * @deprecated since Moodle 2.2 - use moodle exception instead
* This exception must be thrown to the web service client when a web service parameter is invalid
* The error string is gotten from webservice.php
*/
* @param string $errorcode The name of the string from webservice.php to print
* @param string $a The name of the parameter
*/
- function __construct($errorcode=null, $a = '') {
- parent::__construct($errorcode, 'webservice', '', $a, null);
+ function __construct($errorcode=null, $a = '', $debuginfo = null) {
+ parent::__construct($errorcode, 'webservice', '', $a, $debuginfo);
}
}
$updated->data2 = '';
$DB->update_record('assignment_submissions', $updated);
//TODO: add unfinalize action to log
- add_to_log($this->course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->assignment->id, $this->assignment->id, $this->cm->id);
+ add_to_log($this->course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->cm->id.'&userid='.$userid.'&mode='.$mode.'&offset='.$offset, $this->assignment->id, $this->cm->id);
$submission = $this->get_submission($userid);
$this->update_grade($submission);
}
require_once("../../config.php");
require_once("lib.php");
require_once('delete_template_form.php');
+require_once($CFG->libdir.'/tablelib.php');
// $SESSION->feedback->current_tab = 'templates';
$current_tab = 'templates';
}
if(isset($formdata->confirmdelete) AND $formdata->confirmdelete == 1){
- feedback_delete_template($formdata->deletetempl);
+ if(!$template = $DB->get_record("feedback_template", array("id"=>$deletetempl))) {
+ print_error('error');
+ }
+
+ if($template->ispublic) {
+ $systemcontext = get_system_context();
+ require_capability('mod/feedback:createpublictemplate', $systemcontext);
+ require_capability('mod/feedback:deletetemplate', $systemcontext);
+ }
+
+ feedback_delete_template($template);
redirect($deleteurl->out(false));
}
/// Print the page header
$strfeedbacks = get_string("modulenameplural", "feedback");
$strfeedback = get_string("modulename", "feedback");
+$strdeletefeedback = get_string('delete_template','feedback');
$PAGE->set_heading(format_string($course->fullname));
$PAGE->set_title(format_string($feedback->name));
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
-echo $OUTPUT->heading(get_string('delete_template','feedback'));
+echo $OUTPUT->heading($strdeletefeedback);
if($shoulddelete == 1) {
echo $OUTPUT->box_start('generalbox errorboxcontent boxaligncenter boxwidthnormal');
$mform->display();
echo $OUTPUT->box_end();
}else {
- $templates = feedback_get_template_list($course, true);
- echo '<div class="mdl-align">';
+ //first we get the own templates
+ $templates = feedback_get_template_list($course, 'own');
if(!is_array($templates)) {
echo $OUTPUT->box(get_string('no_templates_available_yet', 'feedback'), 'generalbox boxaligncenter');
}else {
- echo '<table width="30%">';
- echo '<tr><th>'.get_string('templates', 'feedback').'</th><th> </th></tr>';
+ echo $OUTPUT->heading(get_string('course'), 3);
+ echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal');
+ $tablecolumns = array('template', 'action');
+ $tableheaders = array(get_string('template', 'feedback'), '');
+ $tablecourse = new flexible_table('feedback_template_course_table');
+
+ $tablecourse->define_columns($tablecolumns);
+ $tablecourse->define_headers($tableheaders);
+ $tablecourse->define_baseurl($deleteurl);
+ $tablecourse->column_style('action', 'width', '10%');
+
+ $tablecourse->sortable(false);
+ $tablecourse->set_attribute('width', '100%');
+ $tablecourse->set_attribute('class', 'generaltable');
+ $tablecourse->setup();
+
foreach($templates as $template) {
- echo '<tr><td align="center">'.$template->name.'</td>';
- echo '<td align="center">';
- echo '<form action="delete_template.php" method="post">';
- echo '<input title="'.get_string('delete_template','feedback').'" type="image" src="'.$OUTPUT->pix_url('t/delete') . '" hspace="1" height="11" width="11" border="0" />';
- echo '<input type="hidden" name="deletetempl" value="'.$template->id.'" />';
- echo '<input type="hidden" name="shoulddelete" value="1" />';
- echo '<input type="hidden" name="id" value="'.$id.'" />';
- echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
- echo '</form>';
- echo '</td></tr>';
+ $data = array();
+ $data[] = $template->name;
+ $url = new moodle_url($deleteurl, array(
+ 'id'=>$id,
+ 'deletetempl'=>$template->id,
+ 'shoulddelete'=>1,
+ ));
+
+ $data[] = $OUTPUT->single_button($url, $strdeletefeedback, 'post');
+ $tablecourse->add_data($data);
}
- echo '</table>';
+ $tablecourse->finish_output();
+ echo $OUTPUT->box_end();
}
-?>
- <form name="frm" action="delete_template.php" method="post">
- <input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
- <input type="hidden" name="id" value="<?php echo $id;?>" />
- <input type="hidden" name="canceldelete" value="0" />
- <button type="button" onclick="this.form.canceldelete.value=1;this.form.submit();"><?php print_string('cancel');?></button>
- </form>
- </div>
-<?php
+ //now we get the public templates if it is permitted
+ $systemcontext = get_system_context();
+ if(has_capability('mod/feedback:createpublictemplate', $systemcontext) AND
+ has_capability('mod/feedback:deletetemplate', $systemcontext)) {
+ $templates = feedback_get_template_list($course, 'public');
+ if(!is_array($templates)) {
+ echo $OUTPUT->box(get_string('no_templates_available_yet', 'feedback'), 'generalbox boxaligncenter');
+ }else {
+ echo $OUTPUT->heading(get_string('public', 'feedback'), 3);
+ echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal');
+ $tablecolumns = array('template', 'action');
+ $tableheaders = array(get_string('template', 'feedback'), '');
+ $tablepublic = new flexible_table('feedback_template_public_table');
+
+ $tablepublic->define_columns($tablecolumns);
+ $tablepublic->define_headers($tableheaders);
+ $tablepublic->define_baseurl($deleteurl);
+ $tablepublic->column_style('action', 'width', '10%');
+
+ $tablepublic->sortable(false);
+ $tablepublic->set_attribute('width', '100%');
+ $tablepublic->set_attribute('class', 'generaltable');
+ $tablepublic->setup();
+
+
+ // echo $OUTPUT->heading(get_string('public', 'feedback'), 3);
+ // echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
+ foreach($templates as $template) {
+ $data = array();
+ $data[] = $template->name;
+ $url = new moodle_url($deleteurl, array(
+ 'id'=>$id,
+ 'deletetempl'=>$template->id,
+ 'shoulddelete'=>1,
+ ));
+
+ $data[] = $OUTPUT->single_button($url, $strdeletefeedback, 'post');
+ $tablepublic->add_data($data);
+ }
+ $tablepublic->finish_output();
+ echo $OUTPUT->box_end();
+ }
+ }
+
+ echo $OUTPUT->box_start('boxaligncenter boxwidthnormal');
+ $url = new moodle_url($deleteurl, array(
+ 'id'=>$id,
+ 'canceldelete'=>1,
+ ));
+
+ echo $OUTPUT->single_button($url, get_string('back'), 'post');
+ echo $OUTPUT->box_end();
}
echo $OUTPUT->footer();
//the create_template-form
$create_template_form = new feedback_edit_create_template_form();
-$create_template_form->set_feedbackdata(array('context' => $context));
+$create_template_form->set_feedbackdata(array('context'=>$context, 'course'=>$course));
$create_template_form->set_form_elements();
$create_template_form->set_data(array('id'=>$id, 'do_show'=>'templates'));
$create_template_formdata = $create_template_form->get_data();
if(isset($create_template_formdata->savetemplate) && $create_template_formdata->savetemplate == 1) {
//check the capabilities to create templates
if(!has_capability('mod/feedback:createprivatetemplate', $context) AND
- !has_capability('mod/feedback:createpublictemplate', $context)) {
+ !has_capability('mod/feedback:createpublictemplate', $context)) {
print_error('cannotsavetempl', 'feedback');
}
- if(trim($create_template_formdata->templatename) == '')
- {
+ if(trim($create_template_formdata->templatename) == '') {
$savereturn = 'notsaved_name';
}else {
- //public templates are currently deaktivated
- // if(has_capability('mod/feedback:createpublictemplate', $context)) {
- // $create_template_formdata->ispublic = isset($create_template_formdata->ispublic) ? 1 : 0;
- // }else {
+ //if the feedback is located on the frontpage then templates can be public
+ if(has_capability('mod/feedback:createpublictemplate', get_system_context())) {
+ $create_template_formdata->ispublic = isset($create_template_formdata->ispublic) ? 1 : 0;
+ }else {
$create_template_formdata->ispublic = 0;
- // }
- if(!feedback_save_as_template($feedback, $create_template_formdata->templatename, $create_template_formdata->ispublic))
- {
+ }
+ if(!feedback_save_as_template($feedback, $create_template_formdata->templatename, $create_template_formdata->ispublic)) {
$savereturn = 'failed';
}else {
$savereturn = 'saved';
// visible elements
$templates_options = array();
- if($templates = feedback_get_template_list($this->feedbackdata->course)){//get the templates
- $templates_options[' '] = get_string('select');
- foreach($templates as $template) {
- $templates_options[$template->id] = $template->name;
+ $owntemplates = feedback_get_template_list($this->feedbackdata->course, 'own');
+ $publictemplates = feedback_get_template_list($this->feedbackdata->course, 'public');
+
+ $options = array();
+ if($owntemplates or $publictemplates) {
+ $options[''] = array('' => get_string('choose'));
+
+ if($owntemplates) {
+ $courseoptions = array();
+ foreach($owntemplates as $template) {
+ $courseoptions[$template->id] = $template->name;
+ }
+ $options[get_string('course')] = $courseoptions;
}
+
+ if($publictemplates) {
+ $publicoptions = array();
+ foreach($publictemplates as $template) {
+ $publicoptions[$template->id] = $template->name;
+ }
+ $options[get_string('public', 'feedback')] = $publicoptions;
+ }
+
$attributes = 'onChange="this.form.submit()"';
- $elementgroup[] =& $mform->createElement('select', 'templateid', '', $templates_options, $attributes);
- // buttons
+ $elementgroup[] =& $mform->createElement('selectgroups', 'templateid', '', $options, $attributes);
$elementgroup[] =& $mform->createElement('submit', 'use_template', get_string('use_this_template', 'feedback'));
}else {
$mform->addElement('static', 'info', get_string('no_templates_available_yet', 'feedback'));
$elementgroup[] =& $mform->createElement('static', 'templatenamelabel', get_string('name', 'feedback'));
$elementgroup[] =& $mform->createElement('text', 'templatename', get_string('name', 'feedback'), array('size'=>'40', 'maxlength'=>'200'));
- //public templates are currently deactivated
- // if(has_capability('mod/feedback:createpublictemplate', $this->feedbackdata->context)) {
- // $elementgroup[] =& $mform->createElement('checkbox', 'ispublic', get_string('public', 'feedback'), get_string('public', 'feedback'));
- // }
+ if(has_capability('mod/feedback:createpublictemplate', get_system_context())) {
+ $elementgroup[] =& $mform->createElement('checkbox', 'ispublic', get_string('public', 'feedback'), get_string('public', 'feedback'));
+ }
// buttons
$elementgroup[] =& $mform->createElement('submit', 'create_template', get_string('save_as_new_template', 'feedback'));
//is the item a template?
if(!$item->feedback AND $item->template) {
$template = $DB->get_record('feedback_template', array('id'=>$item->template));
- $context = get_context_instance(CONTEXT_COURSE, $template->course);
+ if($template->ispublic) {
+ $context = get_system_context();
+ }else {
+ $context = get_context_instance(CONTEXT_COURSE, $template->course);
+ }
$filearea = 'template';
}else {
$cm = get_coursemodule_from_instance('feedback', $item->feedback);
/**
* Serves the files included in feedback items like label. Implements needed access control ;-)
*
+ * There are two situations in general where the files will be sent.
+ * 1) filearea = item, 2) filearea = template
+ *
* @param object $course
* @param object $cm
* @param object $context
function feedback_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
global $CFG, $DB;
- require_login($course, false, $cm);
-
$itemid = (int)array_shift($args);
- require_course_login($course, true, $cm);
-
+ //get the item what includes the file
if (!$item = $DB->get_record('feedback_item', array('id'=>$itemid))) {
return false;
}
+
+ //if the filearea is "item" so we check the permissions like view/complete the feedback
+ if($filearea === 'item') {
+ //get the feedback
+ if(!$feedback = $DB->get_record('feedback', array('id'=>$item->feedback))) {
+ return false;
+ }
- if (!has_capability('mod/feedback:view', $context)) {
+ $canload = false;
+ //first check whether the user has the complete capability
+ if(has_capability('mod/feedback:complete', $context)) {
+ $canload = true;
+ }
+
+ //now we check whether the user has the view capability
+ if(has_capability('mod/feedback:view', $context)) {
+ $canload = true;
+ }
+
+ //if the feedback is on frontpage and anonymous and the fullanonymous is allowed
+ //so the file can be loaded too.
+ if(isset($CFG->feedback_allowfullanonymous)
+ AND $CFG->feedback_allowfullanonymous
+ AND $course->id == SITEID
+ AND $feedback->anonymous == FEEDBACK_ANONYMOUS_YES ) {
+ $canload = true;
+ }
+
+ if(!$canload) {
+ return false;
+ }
+ }else if($filearea === 'template') { //now we check files in templates
+ if(!$template = $DB->get_record('feedback_template', array('id'=>$item->template))) {
+ return false;
+ }
+
+ //if the file is not public so the capability edititems has to be there
+ if(!$template->ispublic) {
+ if(!has_capability('mod/feedback:edititems', $context)) {
+ return false;
+ }
+ }else { //on public templates, at least the user has to be logged in
+ if(!isloggedin()) {
+ return false;
+ }
+ }
+ }else {
return false;
}
}
}
- if ($context->contextlevel == CONTEXT_COURSE) {
+ if ($context->contextlevel == CONTEXT_COURSE || $context->contextlevel == CONTEXT_SYSTEM) {
if ($filearea !== 'template') {
return false;
}
return false;
}
-
/**
* this will delete a given instance.
* all referenced data also will be deleted
global $DB;
$templ = new stdClass();
- $templ->course = $courseid;
+ $templ->course = ($ispublic ? 0 : $courseid);
$templ->name = $name;
$templ->ispublic = $ispublic;
return false;
}
- //files in the template_item are in the context of the current course
+ //files in the template_item are in the context of the current course or
+ //if the template is public the files are in the system context
//files in the feedback_item are in the feedback_context of the feedback
- $c_context = get_context_instance(CONTEXT_COURSE, $newtempl->course);
+ if($ispublic) {
+ $s_context = get_system_context();
+ }else {
+ $s_context = get_context_instance(CONTEXT_COURSE, $newtempl->course);
+ }
$cm = get_coursemodule_from_instance('feedback', $feedback->id);
$f_context = get_context_instance(CONTEXT_MODULE, $cm->id);
if ($itemfiles = $fs->get_area_files($f_context->id, 'mod_feedback', 'item', $item->id, "id", false)) {
foreach($itemfiles as $ifile) {
$file_record = new stdClass();
- $file_record->contextid = $c_context->id;
+ $file_record->contextid = $s_context->id;
$file_record->component = 'mod_feedback';
$file_record->filearea = 'template';
$file_record->itemid = $t_item->id;
*
* @global object
* @uses CONTEXT_COURSE
- * @param int $id the templateid
+ * @param object $template the template
* @return void
*/
-function feedback_delete_template($id) {
+function feedback_delete_template($template) {
global $DB;
- $template = $DB->get_record("feedback_template", array("id"=>$id));
-
- //deleting the files from the item
- $fs = get_file_storage();
- $context = get_context_instance(CONTEXT_COURSE, $template->course);
-
-
- if($t_items = $DB->get_records("feedback_item", array("template"=>$id))) {
+ //deleting the files from the item is done by feedback_delete_item
+ if($t_items = $DB->get_records("feedback_item", array("template"=>$template->id))) {
foreach($t_items as $t_item) {
- if ($templatefiles = $fs->get_area_files($context->id, 'mod_feedback', 'template', $t_item->id, "id", false)) {
- $fs->delete_area_files($context->id, 'mod_feedback', 'template', $t_item->id);
- }
+ feedback_delete_item($t_item->id, false, $template);
}
}
- $DB->delete_records("feedback_template", array("id"=>$id));
+ $DB->delete_records("feedback_template", array("id"=>$template->id));
}
/**
$fs = get_file_storage();
+ if(!$template = $DB->get_record('feedback_template', array('id'=>$templateid))) {
+ return false;
+ }
//get all templateitems
if(!$templitems = $DB->get_records('feedback_item', array('template'=>$templateid))) {
return false;
//files in the template_item are in the context of the current course
//files in the feedback_item are in the feedback_context of the feedback
- $c_context = get_context_instance(CONTEXT_COURSE, $feedback->course);
+ if($template->ispublic) {
+ $s_context = get_system_context();
+ }else {
+ $s_context = get_context_instance(CONTEXT_COURSE, $feedback->course);
+ }
$course = $DB->get_record('course', array('id'=>$feedback->course));
$cm = get_coursemodule_from_instance('feedback', $feedback->id);
$f_context = get_context_instance(CONTEXT_MODULE, $cm->id);
$item->position = $item->position + $positionoffset;
$item->id = $DB->insert_record('feedback_item', $item);
-
+
//TODO: moving the files to the new items
- if ($templatefiles = $fs->get_area_files($c_context->id, 'mod_feedback', 'template', $t_item->id, "id", false)) {
+ if ($templatefiles = $fs->get_area_files($s_context->id, 'mod_feedback', 'template', $t_item->id, "id", false)) {
foreach($templatefiles as $tfile) {
$file_record = new stdClass();
$file_record->contextid = $f_context->id;
*
* @global object
* @param object $course
- * @param boolean $onlyown
+ * @param string $onlyownorpublic
* @return array the template recordsets
*/
-function feedback_get_template_list($course, $onlyown = false) {
- global $DB;
+function feedback_get_template_list($course, $onlyownorpublic = '') {
+ global $DB, $CFG;
- if ($onlyown) {
- $templates = $DB->get_records('feedback_template', array('course'=>$course->id));
- } else {
- $templates = $DB->get_records_select('feedback_template', 'course = ? OR ispublic = 1', array($course->id));
+ switch($onlyownorpublic) {
+ case '':
+ $templates = $DB->get_records_select('feedback_template', 'course = ? OR ispublic = 1', array($course->id), 'name');
+ break;
+ case 'own':
+ $templates = $DB->get_records('feedback_template', array('course'=>$course->id), 'name');
+ break;
+ case 'public':
+ $templates = $DB->get_records('feedback_template', array('ispublic'=>1), 'name');
+ break;
}
return $templates;
}
* @uses CONTEXT_MODULE
* @param int $itemid
* @param boolean $renumber should the kept items renumbered Yes/No
+ * @param object $template if the template is given so the items are bound to it
* @return void
*/
-function feedback_delete_item($itemid, $renumber = true){
+function feedback_delete_item($itemid, $renumber = true, $template = false){
global $DB;
//deleting the files from the item
$fs = get_file_storage();
- if (!$cm = get_coursemodule_from_instance('feedback', $item->feedback)) {
- return false;
- }
- $context = get_context_instance(CONTEXT_MODULE, $cm->id);
+
+ if($template) {
+ if($template->ispublic) {
+ $context = get_system_context();
+ }else {
+ $context = get_context_instance(CONTEXT_COURSE, $template->course);
+ }
+ if ($templatefiles = $fs->get_area_files($context->id, 'mod_feedback', 'template', $item->id, "id", false)) {
+ $fs->delete_area_files($context->id, 'mod_feedback', 'template', $item->id);
+ }
+ }else {
+ if (!$cm = get_coursemodule_from_instance('feedback', $item->feedback)) {
+ return false;
+ }
+ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
- if ($itemfiles = $fs->get_area_files($context->id, 'mod_feedback', 'item', $item->id, "id", false)) {
- $fs->delete_area_files($context->id, 'mod_feedback', 'item', $item->id);
+ if ($itemfiles = $fs->get_area_files($context->id, 'mod_feedback', 'item', $item->id, "id", false)) {
+ $fs->delete_area_files($context->id, 'mod_feedback', 'item', $item->id);
+ }
}
$DB->delete_records("feedback_value", array("item"=>$itemid));
*/
- $module->version = 2011051600; // The current module version (Date: YYYYMMDDXX)
+ $module->version = 2011100800; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2010080300; // Requires this Moodle version
$feedback_version_intern = 1; //this version is used for restore older backups
$module->cron = 0; // Period for cron to check this module (secs)
<FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false" PREVIOUS="course" NEXT="intro"/>
<FIELD NAME="intro" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="name" NEXT="introformat"/>
<FIELD NAME="introformat" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="intro" NEXT="externalurl"/>
- <FIELD NAME="externalurl" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="introformat" NEXT="display"/>
+ <FIELD NAME="externalurl" TYPE="text" LENGTH="small" NOTNULL="true" SEQUENCE="false" PREVIOUS="introformat" NEXT="display"/>
<FIELD NAME="display" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="externalurl" NEXT="displayoptions"/>
<FIELD NAME="displayoptions" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="display" NEXT="parameters"/>
<FIELD NAME="parameters" TYPE="text" LENGTH="small" NOTNULL="false" SEQUENCE="false" PREVIOUS="displayoptions" NEXT="timemodified"/>
// Moodle v2.1.0 release upgrade line
// Put any upgrade step following this
+ if ($oldversion < 2011092800) {
+
+ // Changing nullability of field externalurl on table urls to not-null
+ $table = new xmldb_table('url');
+ $field = new xmldb_field('externalurl', XMLDB_TYPE_TEXT, 'small', null,
+ XMLDB_NOTNULL, null, null, 'introformat');
+
+ $DB->set_field_select('url', 'externalurl', $DB->sql_empty(), 'externalurl IS NULL');
+ // Launch change of nullability for field =externalurl
+ $dbman->change_field_notnull($table, $field);
+
+ // url savepoint reached
+ upgrade_mod_savepoint(true, 2011092800, 'url');
+ }
return true;
}
$string['externalurl'] = 'External URL';
$string['framesize'] = 'Frame height';
$string['chooseavariable'] = 'Choose a variable...';
+$string['invalidurl'] = 'Entered URL is invalid';
$string['modulename'] = 'URL';
$string['modulenameplural'] = 'URLs';
$string['neverseen'] = 'Never seen';
//-------------------------------------------------------
$mform->addElement('header', 'content', get_string('contentheader', 'url'));
$mform->addElement('url', 'externalurl', get_string('externalurl', 'url'), array('size'=>'60'), array('usefilepicker'=>true));
+ $mform->addRule('externalurl', null, 'required', null, 'client');
//-------------------------------------------------------
$mform->addElement('header', 'optionssection', get_string('optionsheader', 'url'));
}
}
+ function validation($data, $files) {
+ $errors = parent::validation($data, $files);
+ //Validating Entered url
+ $data['externalurl'] = clean_param($data['externalurl'], PARAM_URL);
+ if (empty($data['externalurl'])) {
+ $errors['externalurl'] = get_string('invalidurl', 'url');
+ }
+ return $errors;
+ }
+
}
defined('MOODLE_INTERNAL') || die;
-$module->version = 2010101400;
+$module->version = 2011092800;
$module->requires = 2010080300; // Requires this Moodle version
$module->cron = 0;
$creator = wiki_get_user_info($version0page->userid);
$a = new StdClass;
$a->date = userdate($this->page->timecreated, get_string('strftimedaydatetime', 'langconfig'));
- $a->username = $creator->username;
+ $a->username = fullname($creator);
echo $OUTPUT->heading(get_string('createddate', 'wiki', $a), 4, 'wiki_headingtime');
if ($vcount > 0) {
$creator = wiki_get_user_info($version0page->userid);
$a = new stdClass();
$a->date = userdate($this->page->timecreated, get_string('strftimedaydatetime', 'langconfig'));
- $a->username = $creator->username;
+ $a->username = fullname($creator);
echo $OUTPUT->heading(get_string('createddate', 'wiki', $a), 4, 'wiki_headingtime');
if ($versioncount > 0) {
/// If there is only one version, we don't need radios nor forms
return $status;
}
+ $prevstep = $this->qa->get_last_step_with_behaviour_var('_try');
+ $prevresponse = $prevstep->get_qt_data();
$prevtries = $this->qa->get_last_behaviour_var('_try', 0);
$prevbest = $pendingstep->get_fraction();
if (is_null($prevbest)) {
$prevbest = 0;
}
+ if ($this->question->is_same_response($response, $prevresponse)) {
+ return question_attempt::DISCARD;
+ }
+
list($fraction, $state) = $this->question->grade_response($response);
$pendingstep->set_fraction(max($prevbest, $this->adjusted_fraction($fraction, $prevtries)));
- if ($state == question_state::$gradedright) {
+ if ($prevstep->get_state() == question_state::$complete) {
+ $pendingstep->set_state(question_state::$complete);
+ } else if ($state == question_state::$gradedright) {
$pendingstep->set_state(question_state::$complete);
} else {
$pendingstep->set_state(question_state::$todo);
return question_attempt::DISCARD;
}
- $laststep = $this->qa->get_last_step();
- $response = $laststep->get_qt_data();
- if (!$this->question->is_gradable_response($response)) {
- $pendingstep->set_state(question_state::$gaveup);
- return question_attempt::KEEP;
- }
-
$prevtries = $this->qa->get_last_behaviour_var('_try', 0);
- $prevbest = $pendingstep->get_fraction();
+ $prevbest = $this->qa->get_fraction();
if (is_null($prevbest)) {
$prevbest = 0;
}
- if ($laststep->has_behaviour_var('_try')) {
- // Last answer was graded, we want to regrade it. Otherwise the answer
- // has changed, and we are grading a new try.
- $prevtries -= 1;
- }
+ $laststep = $this->qa->get_last_step();
+ $response = $laststep->get_qt_data();
+ if (!$this->question->is_gradable_response($response)) {
+ $state = question_state::$gaveup;
+ $fraction = 0;
+ } else {
- list($fraction, $state) = $this->question->grade_response($response);
+ if ($laststep->has_behaviour_var('_try')) {
+ // Last answer was graded, we want to regrade it. Otherwise the answer
+ // has changed, and we are grading a new try.
+ $prevtries -= 1;
+ }
+
+ list($fraction, $state) = $this->question->grade_response($response);
+
+ $pendingstep->set_behaviour_var('_try', $prevtries + 1);
+ $pendingstep->set_behaviour_var('_rawfraction', $fraction);
+ $pendingstep->set_new_response_summary($this->question->summarise_response($response));
+ }
- $pendingstep->set_fraction(max($prevbest, $this->adjusted_fraction($fraction, $prevtries)));
$pendingstep->set_state($state);
- $pendingstep->set_behaviour_var('_try', $prevtries + 1);
- $pendingstep->set_behaviour_var('_rawfraction', $fraction);
- $pendingstep->set_new_response_summary($this->question->summarise_response($response));
+ $pendingstep->set_fraction(max($prevbest, $this->adjusted_fraction($fraction, $prevtries)));
return question_attempt::KEEP;
}
+
+ /**
+ * Got the most recently graded step. This is mainly intended for use by the
+ * renderer.
+ * @return question_attempt_step the most recently graded step.
+ */
+ public function get_graded_step() {
+ $step = $this->qa->get_last_step_with_behaviour_var('_try');
+ if ($step->has_behaviour_var('_try')) {
+ return $step;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Determine whether a question state represents an "improvable" result,
+ * that is, whether the user can still improve their score.
+ *
+ * @param question_state $state the question state.
+ * @return bool whether the state is improvable
+ */
+ public function is_state_improvable(question_state $state) {
+ return $state == question_state::$todo;
+ }
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_adaptive_renderer extends qbehaviour_renderer {
- protected function get_graded_step(question_attempt $qa) {
- foreach ($qa->get_reverse_step_iterator() as $step) {
- if ($step->has_behaviour_var('_try')) {
- return $step;
- }
- }
- }
public function controls(question_attempt $qa, question_display_options $options) {
return $this->submit_button($qa, $options);
public function feedback(question_attempt $qa, question_display_options $options) {
// Try to find the last graded step.
- $gradedstep = $this->get_graded_step($qa);
+ $gradedstep = $qa->get_behaviour()->get_graded_step($qa);
if (is_null($gradedstep) || $qa->get_max_mark() == 0 ||
$options->marks < question_display_options::MARK_AND_MAX) {
return '';
}
$output = '';
- // print details of grade adjustment due to penalties
+ // Print details of grade adjustment due to penalties
if ($mark->raw != $mark->cur) {
$output .= ' ' . get_string('gradingdetailsadjustment', 'qbehaviour_adaptive', $mark);
}
- // print info about new penalty
- // penalty is relevant only if the answer is not correct and further attempts are possible
- if (!$qa->get_state()->is_finished()) {
+ // Print information about any new penalty, only relevant if the answer can be improved.
+ if ($qa->get_behaviour()->is_state_improvable($qa->get_state())) {
$output .= ' ' . get_string('gradingdetailspenalty', 'qbehaviour_adaptive',
format_float($qa->get_question()->penalty, $options->markdp));
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qbehaviour_adaptive_walkthrough_test extends qbehaviour_walkthrough_test_base {
+ protected function get_contains_penalty_info_expectation($penalty) {
+ $penaltyinfo = get_string('gradingdetailspenalty', 'qbehaviour_adaptive',
+ format_float($penalty, $this->displayoptions->markdp));
+ return new PatternExpectation('/'.preg_quote($penaltyinfo).'/');
+ }
+
+ protected function get_does_not_contain_penalty_info_expectation() {
+ $penaltyinfo = get_string('gradingdetailspenalty', 'qbehaviour_adaptive', 'XXXXX');
+ $penaltypattern = '/'.str_replace('XXXXX', '\\w*', preg_quote($penaltyinfo)).'/';
+ return new NoPatternExpectation($penaltypattern);
+ }
+
public function test_adaptive_multichoice() {
// Create a multiple choice, single response question.
$this->get_contains_mc_radio_expectation($wrongindex, true, true),
$this->get_contains_mc_radio_expectation(($wrongindex + 1) % 3, true, false),
$this->get_contains_mc_radio_expectation(($wrongindex + 2) % 3, true, false),
- $this->get_contains_incorrect_expectation());
+ $this->get_contains_incorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33));
$this->assertPattern('/B|C/',
$this->quba->get_response_summary($this->slot));
$this->get_contains_mc_radio_expectation(($rightindex + 1) % 3, true, false),
$this->get_contains_mc_radio_expectation(($rightindex + 2) % 3, true, false),
$this->get_contains_correct_expectation(),
- new PatternExpectation('/' . preg_quote(
- get_string('gradingdetailspenalty', 'qbehaviour_adaptive',
- format_float($mc->penalty, $this->displayoptions->markdp))) . '/'));
+ $this->get_does_not_contain_penalty_info_expectation());
$this->assertEqual('A',
$this->quba->get_response_summary($this->slot));
// Now change the correct answer to the question, and regrade.
$mc->answers[13]->fraction = -0.33333333;
- $mc->answers[15]->fraction = 1;
+ $mc->answers[14]->fraction = 1; // We don't know which "wrong" index we chose above!
+ $mc->answers[15]->fraction = 1; // Therefore, treat answers B and C with the same score.
$this->quba->regrade_all_questions();
// Verify.
$this->get_contains_partcorrect_expectation());
$autogradedstep = $this->get_step($this->get_step_count() - 2);
- $this->assertWithinMargin($autogradedstep->get_fraction(), 0, 0.0000001);
+ $this->assertWithinMargin($autogradedstep->get_fraction(), 1, 0.0000001);
}
public function test_adaptive_multichoice2() {
$this->check_current_output(
$this->get_contains_mark_summary(2),
$this->get_contains_submit_button_expectation(true),
- $this->get_contains_correct_expectation());
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation());
- // Save the same correct answer again. Should no do anything.
+ // Save the same correct answer again. Should not do anything.
$numsteps = $this->get_step_count();
$this->process_submission(array('choice0' => 1, 'choice2' => 1));
// Verify.
$this->check_step_count($numsteps);
+ $this->check_current_mark(2);
$this->check_current_state(question_state::$complete);
// Finish the attempt.
$this->get_contains_correct_expectation());
}
+ public function test_adaptive_shortanswer_partially_right() {
+
+ // Create a short answer question
+ $sa = test_question_maker::make_a_shortanswer_question();
+ $this->start_attempt_at_question($sa, 'adaptive');
+
+ // Check the initial state.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(null);
+ $this->check_current_output(
+ $this->get_contains_marked_out_of_summary(),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_feedback_expectation());
+
+ // Submit a partially correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'toad'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0.8);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.8),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_partcorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit an incorrect answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0.8);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.8),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit a correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'frog'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(0.8);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.8),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Finish the attempt.
+ $this->quba->finish_all_questions();
+
+ // Verify.
+ $this->check_current_state(question_state::$gradedright);
+ $this->check_current_mark(0.8);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.8),
+ $this->get_contains_submit_button_expectation(false),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+ }
+
+ public function test_adaptive_shortanswer_wrong_right_wrong() {
+
+ // Create a short answer question
+ $sa = test_question_maker::make_a_shortanswer_question();
+ $this->start_attempt_at_question($sa, 'adaptive');
+
+ // Check the initial state.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(null);
+ $this->check_current_output(
+ $this->get_contains_marked_out_of_summary(),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_feedback_expectation());
+
+ // Submit a wrong answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit the same wrong answer again. Nothing should change.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit a correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'frog'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit another incorrect answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Finish the attempt.
+ $this->quba->finish_all_questions();
+
+ // Verify.
+ $this->check_current_state(question_state::$gradedwrong);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(false),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+ }
+
+ public function test_adaptive_shortanswer_invalid_after_complete() {
+
+ // Create a short answer question
+ $sa = test_question_maker::make_a_shortanswer_question();
+ $this->start_attempt_at_question($sa, 'adaptive');
+
+ // Check the initial state.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(null);
+ $this->check_current_output(
+ $this->get_contains_marked_out_of_summary(),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_feedback_expectation());
+
+ // Submit a wrong answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'hippopotamus'));
+
+ // Verify.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(0);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit a correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'frog'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit an empty answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => ''));
+
+ // Verify.
+ $this->check_current_state(question_state::$invalid);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_contains_validation_error_expectation());
+
+ // Submit another wrong answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => 'bumblebee'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Finish the attempt.
+ $this->quba->finish_all_questions();
+
+ // Verify.
+ $this->check_current_state(question_state::$gradedwrong);
+ $this->check_current_mark(0.66666667);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(0.67),
+ $this->get_contains_submit_button_expectation(false),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+ }
+
public function test_adaptive_shortanswer_try_to_submit_blank() {
// Create a short answer question with correct answer true.
$this->get_contains_marked_out_of_summary(),
$this->get_contains_submit_button_expectation(true),
$this->get_does_not_contain_correctness_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
$this->get_contains_validation_error_expectation());
$this->assertNull($this->quba->get_response_summary($this->slot));
$this->get_contains_mark_summary(0.8),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_partcorrect_expectation(),
+ $this->get_contains_penalty_info_expectation(0.33),
$this->get_does_not_contain_validation_error_expectation());
// Now submit blank again.
$this->get_contains_mark_summary(0.8),
$this->get_contains_submit_button_expectation(true),
$this->get_contains_partcorrect_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
$this->get_contains_validation_error_expectation());
}
+
+ public function test_adaptive_numerical() {
+
+ // Create a numerical question
+ $sa = test_question_maker::make_question('numerical', 'pi');
+ $this->start_attempt_at_question($sa, 'adaptive');
+
+ // Check the initial state.
+ $this->check_current_state(question_state::$todo);
+ $this->check_current_mark(null);
+ $this->check_current_output(
+ $this->get_contains_marked_out_of_summary(),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_does_not_contain_feedback_expectation());
+
+ // Submit the correct answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => '3.14'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(1);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(1),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_correct_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Submit an incorrect answer.
+ $this->process_submission(array('-submit' => 1, 'answer' => '-5'));
+
+ // Verify.
+ $this->check_current_state(question_state::$complete);
+ $this->check_current_mark(1);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(1),
+ $this->get_contains_submit_button_expectation(true),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_penalty_info_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+
+ // Finish the attempt.
+ $this->quba->finish_all_questions();
+
+ // Verify.
+ $this->check_current_state(question_state::$gradedwrong);
+ $this->check_current_mark(1);
+ $this->check_current_output(
+ $this->get_contains_mark_summary(1),
+ $this->get_contains_submit_button_expectation(false),
+ $this->get_contains_incorrect_expectation(),
+ $this->get_does_not_contain_validation_error_expectation());
+ }
}
// Now change the correct answer to the question, and regrade.
$mc->answers[13]->fraction = -0.33333333;
- $mc->answers[15]->fraction = 1;
+ $mc->answers[14]->fraction = 1; // We don't know which "wrong" index we chose above!
+ $mc->answers[15]->fraction = 1; // Therefore, treat answers B and C with the same score.
$this->quba->regrade_all_questions();
// Verify.
$this->get_contains_mark_summary(1),
$this->get_contains_partcorrect_expectation());
- $autogradedstep = $this->get_step($this->get_step_count() - 2);
- $this->assertWithinMargin($autogradedstep->get_fraction(), 0, 0.0000001);
+ $autogradedstep = $this->get_step($this->get_step_count() - 3);
+ $this->assertWithinMargin($autogradedstep->get_fraction(), 1, 0.0000001);
}
public function test_multichoice2() {
return new question_attempt_step_read_only();
}
+ /**
+ * Get the last step with a particular behaviour variable set.
+ * @param string $name the name of the variable to get.
+ * @return question_attempt_step the last step, or a step with no variables
+ * if there was not a real step.
+ */
+ public function get_last_step_with_behaviour_var($name) {
+ foreach ($this->get_reverse_step_iterator() as $step) {
+ if ($step->has_behaviour_var($name)) {
+ return $step;
+ }
+ }
+ return new question_attempt_step_read_only();
+ }
+
/**
* Get the latest value of a particular question type variable. That is, get
* the value from the latest step that has it set. Return null if it is not
<li>change their question type (numerical, shortanswer, multiple choice). </li></ul>
';
$string['questionsless'] = '{$a} question(s) less than in the multianswer question stored in the database';
-$string['questionsmissing'] = 'No valid questions, create at least one question';
+$string['questionsmissing'] = 'The question text must include at least one embedded answer.';
$string['questionsmore'] = '{$a} question(s) more than in the multianswer question stored in the database';
$string['questionnotfound'] = 'Unable to find question of question part #{$a}';
$string['questionsaveasedited'] = 'The question will be saved as edited';
$prevresponse, $newresponse, 'unit');
}
- return false;
+ return true;
}
public function get_correct_response() {
/** Path: theme pagelayout **/
-body {margin:auto 0px;width:auto; height: 100%}
-#page {width:100%; min-height: 100%;}
+body {margin:auto 0px;
+ width:auto;
+ height: 100%
+}
+#page {
+ width:100%;
+ min-height: 100%;
+}
#page-content {
clear: both;
position: relative;
- width: 100%;min-height: 100%;
+ width: 100%;
+ min-height: 100%;
}
-
#page-content #region-main-box {
float: left;
margin-left: -200px;
position: relative;
width: 200%;
- right: 100%;min-height: 100%;
+ right: 100%;
+ min-height: 100%;
}
-
#page-content #region-post-box {
float: left;
margin-left: -200px;
- width: 100%;min-height: 100%;
+ width: 100%;
+ min-height: 100%;
}
-
#page-content #region-main-wrap {
float: left;
- width: 50%;min-height: 100%;
+ width: 50%;
+ min-height: 100%;
}
-
#page-content #region-main {
position: relative;
margin-left: 400px;
- left: 100%;min-height: 100%;
+ left: 100%;
+ min-height: 100%;
}
-
#page-content #region-pre {
float: right;
position: relative;
left: 200px;
min-height: 100%;
}
-
#page-content #region-post {
float: right;
position: relative;
left: 600px;
- width: 200px;min-height: 100%;
+ width: 200px;
+ min-height: 100%;
}
-
#page-content #region-main .region-content {
overflow: hidden;
- padding: 20px 20px 20px 0;min-height: 100%;
+ padding: 20px 20px 20px 0;
+ min-height: 100%;
}
-
.pagelayout-report #page-content #region-main .region-content {
overflow: auto;
- padding-bottom:0;
- margin-bottom:20px;
+ padding-bottom: 0;
+ margin-bottom: 20px;
}
-
#page-content #region-pre .region-content,
#page-content #region-post .region-content {
overflow: hidden;
padding: 20px 10px;
min-height: 100%;
}
-
#page-footer {
clear: both;
float: left;
/** Only side pre **/
.side-pre-only #page-content #region-main-box {
- margin-left: 0px;
+ margin-left: 0;
}
-
.side-pre-only #page-content #region-main-box #region-post-box {
margin-left: -200px;
}
-
.side-pre-only #page-content #region-main-box #region-post-box #region-main-wrap #region-main {
margin-left: 200px;
}
-
.side-pre-only #page-content #region-main-box #region-post-box #region-pre {
left: 200px;
width: 200px;
}
-
.side-pre-only #page-content #region-main-box #region-post-box #region-post {
- width: 0%;
+ width: 0;
}
/** Only side post **/
.side-post-only #page-content #region-main-box {
- margin-left: 0px;
+ margin-left: 0;
}
-
.side-post-only #page-content #region-main-box #region-post-box {
margin-left: -200px;
}
-
.side-post-only #page-content #region-main-box #region-post-box #region-main-wrap #region-main {
margin-left: 200px;
}
-
+.side-post-only #page-content #region-main-box #region-post-box #region-pre {
+ left: 0;
+ width: 0;
+}
.side-post-only #page-content #region-main-box #region-post-box #region-post {
- left: 400px;
+ left: 200px;
width: 200px;
}
-
+.blocks-moving.side-post-only #page-content #region-main-box {
+ float: left;
+ margin-left: -200px;
+ position: relative;
+ width: 200%;
+ right: 100%;min-height: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box {
+ float: left;
+ margin-left: -200px;
+ width: 100%;min-height: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-main-wrap {
+ float: left;
+ width: 50%;
+ min-height: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-main-wrap #region-main {
+ position: relative;
+ margin-left: 400px;
+ left: 100%;
+ min-height: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-pre {
+ float: right;
+ position: relative;
+ width: 200px;
+ left: 200px;
+ min-height: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-post {
+ float: right;
+ position: relative;
+ left: 600px;
+ width: 200px;
+ min-height: 100%;
+}
.has_dock.side-post-only .page-middle #region-main-box #region-post-box #region-main-wrap #region-main {
margin-left: 200px;
}
/** No blocks whatsoever **/
.content-only #page-content #region-main-box {
- margin-left: 0px;
+ margin-left: 0;
}
-
.content-only #page-content #region-main-box #region-post-box {
- margin-left: 0px;
+ margin-left: 0;
}
-
.content-only #page-content #region-main-box #region-post-box #region-main-wrap #region-main {
- margin-left: 0px;
+ margin-left: 0;
}
-
.content-only #page-content #region-main-box #region-post-box #region-pre {
- width: 0px;
+ width: 0;
}
-
.content-only #page-content #region-main-box #region-post-box #region-post {
- width: 0px;
+ width: 0;
}
\ No newline at end of file
/** Path: theme pagelayout **/
/*********************************************************************************************
-
- left column: 230px
- right column: 330px
- padding left/right column: 10px
- padding center column: 30px
-
+ column witdh: [[setting:regionwidth]]
**********************************************************************************************/
body {
width: 100%;
}
-
-
/* @end */
/* @group Pre Side Only */
width: 0%;
}
-
-
/* @end */
/* @group Post Side Only */
margin-left: [[setting:regionwidth]];
}
+.side-post-only #page-content #region-main-box #region-post-box #region-pre {
+ left: 0;
+ width: 0;
+}
+
.side-post-only #page-content #region-main-box #region-post-box #region-post {
- left: [[setting:regionwidthdouble]];
+ left: [[setting:regionwidth]];
width: [[setting:regionwidth]];
}
margin-left: 200px;
}
+.blocks-moving.side-post-only #page-content #region-main-box {
+ float: left;
+ margin-left: -[[setting:regionwidth]];
+ position: relative;
+ width: 200%;
+ right: 100%;
+}
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box {
+ float: left;
+ margin-left: -[[setting:regionwidth]];
+ width: 100%;
+ border-right: 2px solid #98bcd6;
+ background: url([[pix:theme|top_bg]]) repeat-x top #fff;
+}
+
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-main-wrap {
+ float: left;
+ width: 50%;
+}
+
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-main-wrap #region-main {
+ overflow: hidden;
+ position: relative;
+ margin-left: [[setting:regionwidthdouble]];
+ left: 100%;
+}
+
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-pre {
+ float: right;
+ position: relative;
+ left: [[setting:leftregionwidthmargin]];
+ width: [[setting:regionwidth]];
+ background: transparent;
+}
+
+.blocks-moving.side-post-only #page-content #region-main-box #region-post-box #region-post {
+ float: right;
+ position: relative;
+ left: [[setting:rightregionwidthmargin]];
+ width: [[setting:regionwidth]];
+ background: transparent;
+}
/* @end */
width: 0px;
}
+/* @end */
+/* @pagelayout-report - overflow */
-/* @end */
.pagelayout-report #page-content #region-main {
- overflow:auto;
+ overflow: auto;
}
.pagelayout-report #page-content #region-main .region-content {
- overflow:visible;
+ overflow: visible;
}
\ No newline at end of file
$this->zend_server->setReturnResponse(true);
//TODO: the error handling in Zend Soap server is useless, XML-RPC is much, much better :-(
$this->zend_server->registerFaultException('moodle_exception');
- $this->zend_server->registerFaultException('webservice_parameter_exception');
+ $this->zend_server->registerFaultException('webservice_parameter_exception'); //deprecated since Moodle 2.2 - kept for backward compatibility
$this->zend_server->registerFaultException('invalid_parameter_exception');
$this->zend_server->registerFaultException('invalid_response_exception');
}