if ($interactive) {
cli_separator();
$languages = get_string_manager()->get_list_of_translations();
- // format the langs nicely - 3 per line
- $c = 0;
- $langlist = '';
- foreach ($languages as $key=>$lang) {
- $c++;
- $length = iconv_strlen($lang, 'UTF-8');
- $padded = $lang.str_repeat(' ', 38-$length);
- $langlist .= $padded;
- if ($c % 3 == 0) {
- $langlist .= "\n";
- }
- }
+ // Do not put the langs into columns because it is not compatible with RTL.
+ $langlist = implode("\n", $languages);
$default = $CFG->lang;
cli_heading(get_string('availablelangs', 'install'));
echo $langlist."\n";
$copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
'<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
'Copyright © 1999 onwards, Martin Dougiamas<br />'.
- 'and <a href="http://docs.moodle.org/dev/Credits">many other contributors</a>.<br />'.
+ 'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
'<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
//////////////////////////////////////////////////////////////////////////////////////////////////
list($insql, $inparams) = $DB->get_in_or_equal($filter->component, SQL_PARAMS_NAMED);
$csql = "SELECT COUNT(*)";
- $fsql = "SELECT s.id, s.*, c.name AS component";
+ $fsql = "SELECT s.*, c.name AS component";
$sql = " FROM {tool_customlang_components} c
JOIN {tool_customlang} s ON s.componentid = c.id
WHERE s.lang = :lang
#page-admin-tool-customlang-index .continuebutton {
margin-top: 1em;
}
+
+.path-admin-tool-customlang #translator .standard.master.cell.c2 {
+ word-break: break-all;
+}
$string['check_indexes'] = 'Look for missing DB indexes';
$string['checkoraclesemantics'] = 'Check semantics';
$string['check_oracle_semantics'] = 'Look for incorrect length semantics';
+$string['duplicateindexname'] = 'Duplicate index name';
$string['incorrectfieldname'] = 'Incorrect name';
$string['index'] = 'Index';
$string['indexes'] = 'Indexes';
+$string['indexnameempty'] = 'Index name is empty';
$string['integerincorrectlength'] = 'Incorrect length for integer field';
+$string['incorrectindexname'] = 'Incorrect index name';
$string['incorrectkeyname'] = 'Incorrect key name';
$string['incorrecttablename'] = 'Incorrect table name';
$string['key'] = 'Key';
//add the missing capabilities to the allowed users object to be displayed by renderer
foreach ($allowedusers as &$alloweduser) {
- if (!is_siteadmin($alloweduser->id) and key_exists($alloweduser->id, $usersmissingcaps)) {
+ if (!is_siteadmin($alloweduser->id) and array_key_exists($alloweduser->id, $usersmissingcaps)) {
$alloweduser->missingcapabilities = implode(', ', $usersmissingcaps[$alloweduser->id]);
}
}
$extra = $DB->get_records_sql($sql);
$keys = array_keys($courses);
- $defaultrole = reset(get_archetype_roles('student'));
- //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
- foreach ($keys AS $id) {
- if ($courses[$id]->visible == 0) {
- unset($courses[$id]);
- continue;
+ $studentroles = get_archetype_roles('student');
+ if (!empty($studentroles)) {
+ $defaultrole = reset($studentroles);
+ //$defaultrole = get_default_course_role($ccache[$shortname]); //TODO: rewrite this completely, there is no default course role any more!!!
+ foreach ($keys AS $id) {
+ if ($courses[$id]->visible == 0) {
+ unset($courses[$id]);
+ continue;
+ }
+ $courses[$id]->cat_id = $courses[$id]->category;
+ $courses[$id]->defaultroleid = $defaultrole->id;
+ unset($courses[$id]->category);
+ unset($courses[$id]->visible);
+
+ $courses[$id]->cat_name = $extra[$id]->cat_name;
+ $courses[$id]->cat_description = $extra[$id]->cat_description;
+ $courses[$id]->defaultrolename = $defaultrole->name;
+ // coerce to array
+ $courses[$id] = (array)$courses[$id];
}
- $courses[$id]->cat_id = $courses[$id]->category;
- $courses[$id]->defaultroleid = $defaultrole->id;
- unset($courses[$id]->category);
- unset($courses[$id]->visible);
-
- $courses[$id]->cat_name = $extra[$id]->cat_name;
- $courses[$id]->cat_description = $extra[$id]->cat_description;
- $courses[$id]->defaultrolename = $defaultrole->name;
- // coerce to array
- $courses[$id] = (array)$courses[$id];
+ } else {
+ throw new moodle_exception('unknownrole', 'error', '', 'student');
}
} else {
// if the array is empty, send it anyway
/// Check if the user has actually submitted login data to us
- if ($shibbolethauth->user_login($frm->username, $frm->password)) {
+ if ($shibbolethauth->user_login($frm->username, $frm->password)
+ && $user = authenticate_user_login($frm->username, $frm->password)) {
- $user = authenticate_user_login($frm->username, $frm->password);
enrol_check_plugins($user);
session_set_user($user);
}
else {
- // For some weird reason the Shibboleth user couldn't be authenticated
+ // The Shibboleth user couldn't be mapped to a valid Moodle user
+ print_error('shib_invalid_account_error', 'auth_shibboleth');
}
}
$string['auth_shib_only'] = 'Shibboleth only';
$string['auth_shib_only_description'] = 'Check this option if a Shibboleth authentication shall be enforced';
$string['auth_shib_username_description'] = 'Name of the webserver Shibboleth environment variable that shall be used as Moodle username';
+$string['shib_invalid_account_error'] = 'You seem to be Shibboleth authenticated but Moodle has no valid account for your username. Your account may not exist or it may have been suspended.';
$string['shib_no_attributes_error'] = 'You seem to be Shibboleth authenticated but Moodle didn\'t receive any user attributes. Please check that your Identity Provider releases the necessary attributes ({$a}) to the Service Provider Moodle is running on or inform the webmaster of this server.';
$string['shib_not_all_attributes_error'] = 'Moodle needs certain Shibboleth attributes which are not present in your case. The attributes are: {$a}<br />Please contact the webmaster of this server or your Identity Provider.';
$string['shib_not_set_up_error'] = 'Shibboleth authentication doesn\'t seem to be set up correctly because no Shibboleth environment variables are present for this page. Please consult the <a href="README.txt">README</a> for further instructions on how to set up Shibboleth authentication or contact the webmaster of this Moodle installation.';
}
$currentfullname = $fullname.$suffixfull;
$currentshortname = substr($shortname, 0, 100 - strlen($suffixshort)).$suffixshort; // < 100cc
- $coursefull = $DB->get_record_select('course', 'fullname = ? AND id != ?', array($currentfullname, $courseid));
+ $coursefull = $DB->get_record_select('course', 'fullname = ? AND id != ?',
+ array($currentfullname, $courseid), '*', IGNORE_MULTIPLE);
$courseshort = $DB->get_record_select('course', 'shortname = ? AND id != ?', array($currentshortname, $courseid));
$counter++;
} while ($coursefull || $courseshort);
$this->assertEquals(date('w-15:00', strtotime('tomorrow')), date('w-H:i', $next));
// Let's have a Belgian beer! (UTC+1 / UTC+2 DST).
+ // Warning: Some of these tests will fail if executed "around"
+ // 'Europe/Brussels' DST changes (last Sunday in March and
+ // last Sunday in October right now - 2012). Once Moodle
+ // moves to PHP TZ support this could be fixed properly.
date_default_timezone_set('Europe/Brussels');
$now = strtotime('18:00:00');
- $dst = date('I');
+ $dst = date('I', $now);
$timezone = -10.0; // 7am for the user.
$next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
$this->assertEquals($expected, date('w-H:i', $next));
// The big apple! (UTC-5 / UTC-4 DST).
+ // Warning: Some of these tests will fail if executed "around"
+ // 'America/New_York' DST changes (2nd Sunday in March and
+ // 1st Sunday in November right now - 2012). Once Moodle
+ // moves to PHP TZ support this could be fixed properly.
date_default_timezone_set('America/New_York');
$now = strtotime('18:00:00');
- $dst = date('I');
+ $dst = date('I', $now);
$timezone = -10.0; // 1pm for the user.
$next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
set_config('backup_auto_hour', '20', 'backup');
set_config('backup_auto_minute', '00', 'backup');
+ // Note: These tests should not fail because they are "unnafected"
+ // by DST changes, as far as execution always happens on Monday and
+ // Saturday and those week days are not, right now, the ones rulez
+ // to peform the DST changes (Sunday is). This may change if rules
+ // are modified in the future.
date_default_timezone_set('Europe/Brussels');
$now = strtotime('next Monday 18:00:00');
- $dst = date('I');
+ $dst = date('I', $now);
$timezone = -12.0; // 1pm for the user.
$next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
set_config('backup_auto_hour', '02', 'backup');
set_config('backup_auto_minute', '00', 'backup');
+ // Note: These tests should not fail because they are "unnafected"
+ // by DST changes, as far as execution always happens on Monday and
+ // Saturday and those week days are not, right now, the ones rulez
+ // to peform the DST changes (Sunday is). This may change if rules
+ // are modified in the future.
date_default_timezone_set('America/New_York');
$now = strtotime('next Monday 04:00:00');
- $dst = date('I');
+ $dst = date('I', $now);
$timezone = -12.0; // 8pm for the user.
$next = backup_cron_automated_helper::calculate_next_automated_backup($timezone, $now);
$options = array();
$firsthub = false;
foreach ($hubs as $hub) {
- if (key_exists('id', $hub)) {
+ if (array_key_exists('id', $hub)) {
$params = array('hubid' => $hub['id'],
'filetype' => HUB_HUBSCREENSHOT_FILE_TYPE);
$imgurl = new moodle_url(HUB_HUBDIRECTORYURL .
break;
}
- if (Y.UA.ie > 7) {
+ if (Y.UA.ie == 8) {
// IE8 can flip the text via CSS but not handle SVG
title.setContent(text);
title.setAttribute('style', 'writing-mode: tb-rl; filter: flipV flipH;display:inline;');
placeholder.replace(this.Y.Node.getDOMNode(this.cachedcontentnode));
this.cachedcontentnode = this.Y.one('#'+this.cachedcontentnode.get('id'));
- var commands = this.cachedcontentnode.one('.title .commands');
+ var commands = dockitem.commands;
if (commands) {
commands.all('.hidepanelicon').remove();
commands.all('.moveto').remove();
* @param bool $forcedownload whether or not force download
* @param array $options additional options affecting the file serving
* @return bool
+ * @todo MDL-36050 improve capability check on stick blocks, so we can check user capability before sending images.
*/
function block_html_pluginfile($course, $birecord_or_cm, $context, $filearea, $args, $forcedownload, array $options=array()) {
- global $SCRIPT;
+ global $DB, $CFG;
if ($context->contextlevel != CONTEXT_BLOCK) {
send_file_not_found();
}
- require_course_login($course);
+ // If block is in course context, then check if user has capability to access course.
+ if ($context->get_course_context(false)) {
+ require_course_login($course);
+ } else if ($CFG->forcelogin) {
+ require_login();
+ } else {
+ // Get parent context and see if user have proper permission.
+ $parentcontext = $context->get_parent_context();
+ if ($parentcontext->contextlevel === CONTEXT_COURSECAT) {
+ // Check if category is visible and user can view this category.
+ $category = $DB->get_record('course_categories', array('id' => $parentcontext->instanceid), '*', MUST_EXIST);
+ if (!$category->visible) {
+ require_capability('moodle/category:viewhiddencategories', $parentcontext);
+ }
+ }
+ // At this point there is no way to check SYSTEM or USER context, so ignoring it.
+ }
if ($filearea !== 'content') {
send_file_not_found();
if (isset($CFG->block_online_users_timetosee)) {
$timetoshowusers = $CFG->block_online_users_timetosee * 60;
}
- $timefrom = 100 * floor((time()-$timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache
+ $now = time();
+ $timefrom = 100 * floor(($now - $timetoshowusers) / 100); // Round to nearest 100 seconds for better query cache
//Calculate if we are in separate groups
$isseparategroups = ($this->page->course->groupmode == SEPARATEGROUPS
}
$userfields = user_picture::fields('u', array('username'));
-
+ $params['now'] = $now;
+ $params['timefrom'] = $timefrom;
if ($this->page->course->id == SITEID or $this->page->context->contextlevel < CONTEXT_COURSE) { // Site-level
$sql = "SELECT $userfields, MAX(u.lastaccess) AS lastaccess
FROM {user} u $groupmembers
- WHERE u.lastaccess > $timefrom
+ WHERE u.lastaccess > :timefrom
+ AND u.lastaccess <= :now
+ AND u.deleted = 0
$groupselect
GROUP BY $userfields
ORDER BY lastaccess DESC ";
$csql = "SELECT COUNT(u.id)
FROM {user} u $groupmembers
- WHERE u.lastaccess > $timefrom
+ WHERE u.lastaccess > :timefrom
+ AND u.lastaccess <= :now
+ AND u.deleted = 0
$groupselect";
} else {
$sql = "SELECT $userfields, MAX(ul.timeaccess) AS lastaccess
FROM {user_lastaccess} ul $groupmembers, {user} u
JOIN ($esqljoin) euj ON euj.id = u.id
- WHERE ul.timeaccess > $timefrom
+ WHERE ul.timeaccess > :timefrom
AND u.id = ul.userid
AND ul.courseid = :courseid
+ AND ul.timeaccess <= :now
+ AND u.deleted = 0
$groupselect
GROUP BY $userfields
ORDER BY lastaccess DESC";
$csql = "SELECT COUNT(u.id)
FROM {user_lastaccess} ul $groupmembers, {user} u
JOIN ($esqljoin) euj ON euj.id = u.id
- WHERE ul.timeaccess > $timefrom
+ WHERE ul.timeaccess > :timefrom
AND u.id = ul.userid
AND ul.courseid = :courseid
+ AND ul.timeaccess <= :now
+ AND u.deleted = 0
$groupselect";
$params['courseid'] = $this->page->course->id;
}
foreach ($users as $user) {
$this->content->text .= '<li class="listentry">';
- $timeago = format_time(time() - $user->lastaccess); //bruno to calculate correctly on frontpage
+ $timeago = format_time($now - $user->lastaccess); //bruno to calculate correctly on frontpage
if (isguestuser($user)) {
$this->content->text .= '<div class="user">'.$OUTPUT->user_picture($user, array('size'=>16));
$this->content->text = '<div class="searchform">';
$this->content->text .= '<form action="'.$CFG->wwwroot.'/mod/forum/search.php" style="display:inline"><fieldset class="invisiblefieldset">';
+ $this->content->text .= '<legend class="accesshide">'.$strsearch.'</legend>';
$this->content->text .= '<input name="id" type="hidden" value="'.$this->page->course->id.'" />'; // course
$this->content->text .= '<label class="accesshide" for="searchform_search">'.$strsearch.'</label>'.
'<input id="searchform_search" name="search" type="text" size="16" />';
}
/**
- * Remove cohort member
+ * Add cohort member
* @param int $cohortid
* @param int $userid
* @return void
}
/**
- * Add cohort member
+ * Remove cohort member
* @param int $cohortid
* @param int $userid
* @return void
*/
private function setup_course($courseid) {
global $PAGE, $DB;
- if (!empty($this->course)) {
+ if (!empty($this->course) && $this->course->id == $courseid) {
// already set, stop
return;
}
a: document.createElement('a'),
icon: document.createElement('img'),
namespan: document.createElement('span'),
+ groupingspan: document.createElement('span'),
progressouter: document.createElement('span'),
progress: document.createElement('span')
};
resel.div.appendChild(document.createTextNode(' '));
+ resel.groupingspan.className = 'groupinglabel';
+ resel.div.appendChild(resel.groupingspan);
+
resel.progressouter.className = 'dndupload-progress-outer';
resel.progress.className = 'dndupload-progress-inner';
resel.progress.innerHTML = ' ';
resel.icon.src = result.icon;
resel.a.href = result.link;
resel.namespan.innerHTML = result.name;
+
+ if (result.groupingname) {
+ resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+ } else {
+ resel.div.removeChild(resel.groupingspan);
+ }
+
resel.div.removeChild(resel.progressouter);
resel.li.id = result.elementid;
resel.div.innerHTML += result.commands;
resel.icon.src = result.icon;
resel.a.href = result.link;
resel.namespan.innerHTML = result.name;
+
+ if (result.groupingname) {
+ resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+ } else {
+ resel.div.removeChild(resel.groupingspan);
+ }
+
resel.div.removeChild(resel.progressouter);
resel.li.id = result.elementid;
resel.div.innerHTML += result.commands;
$resp->commands = make_editing_buttons($mod, true, true, 0, $mod->sectionnum);
$resp->onclick = $mod->get_on_click();
+ // if using groupings, then display grouping name
+ if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
+ $groupings = groups_get_all_groupings($this->course->id);
+ $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
+ }
+
echo $OUTPUT->header();
echo json_encode($resp);
die();
array('options' => $options));
//retrieve courses
- if (!key_exists('ids', $params['options'])
+ if (!array_key_exists('ids', $params['options'])
or empty($params['options']['ids'])) {
$courses = $DB->get_records('course');
} else {
require_capability('moodle/course:create', $context);
// Make sure lang is valid
- if (key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
+ if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
}
// Make sure theme is valid
- if (key_exists('forcetheme', $course)) {
+ if (array_key_exists('forcetheme', $course)) {
if (!empty($CFG->allowcoursethemes)) {
if (empty($availablethemes[$course['forcetheme']])) {
throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
//set default value for completion
$courseconfig = get_config('moodlecourse');
if (completion_info::is_enabled_for_site()) {
- if (!key_exists('enablecompletion', $course)) {
+ if (!array_key_exists('enablecompletion', $course)) {
$course['enablecompletion'] = $courseconfig->enablecompletion;
}
- if (!key_exists('completionstartonenrol', $course)) {
+ if (!array_key_exists('completionstartonenrol', $course)) {
$course['completionstartonenrol'] = $courseconfig->completionstartonenrol;
}
} else {
function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
$modid, $modaction, $groupid) {
- global $DB;
+ global $DB, $CFG;
$text = get_string('course')."\t".get_string('time')."\t".get_string('ip_address')."\t".
get_string('fullnameuser')."\t".get_string('action')."\t".get_string('info');
$firstField = format_string($courses[$log->course], true, array('context' => $coursecontext));
$fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
$row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info);
+ $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);\r
+ $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action.' ('.$actionurl.')', $log->info);
$text = implode("\t", $row);
echo $text." \n";
}
$myxls->write($row, 2, $log->ip, '');
$fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
$myxls->write($row, 3, $fullname, '');
- $myxls->write($row, 4, $log->module.' '.$log->action, '');
+ $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+ $myxls->write($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')', '');
$myxls->write($row, 5, $log->info, '');
$row++;
$myxls->write_string($row, 2, $log->ip);
$fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
$myxls->write_string($row, 3, $fullname);
- $myxls->write_string($row, 4, $log->module.' '.$log->action);
+ $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+ $myxls->write_string($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')');
$myxls->write_string($row, 5, $log->info);
$row++;
$linkclasses = '';
$textclasses = '';
if ($accessiblebutdim) {
- $linkclasses .= ' dimmed';
- $textclasses .= ' dimmed_text';
+ $linkclasses .= ' dimmed conditionalhidden';
+ $textclasses .= ' dimmed_text conditionalhidden';
$accesstext = '<span class="accesshide">'.
get_string('hiddenfromstudents').': </span>';
} else {
// Display link itself
echo '<a ' . $linkcss . $mod->extra . $onclick .
' href="' . $url . '"><img src="' . $mod->get_icon_url() .
- '" class="activityicon" alt="" /> ' .
+ '" class="activityicon" alt="' . $modulename . '" /> ' .
$accesstext . '<span class="instancename">' .
$instancename . $altname . '</span></a>';
// see the activity itself, or for staff)
if (!$mod->uservisible) {
echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
- } else if ($canviewhidden && !empty($CFG->enableavailability) && $mod->visible) {
+ } else if ($canviewhidden && !empty($CFG->enableavailability)) {
+ $visibilityclass = '';
+ if (!$mod->visible) {
+ $visibilityclass = 'accesshide';
+ }
$ci = new condition_info($mod);
$fullinfo = $ci->get_full_information();
if($fullinfo) {
- echo '<div class="availabilityinfo">'.get_string($mod->showavailability
+ echo '<div class="availabilityinfo '.$visibilityclass.'">'.get_string($mod->showavailability
? 'userrestriction_visible'
: 'userrestriction_hidden','condition',
$fullinfo).'</div>';
if ($sm->string_exists('modulename_link', $modname)) { // Link to further info in Moodle docs
$link = get_string('modulename_link', $modname);
$linktext = get_string('morehelp');
- $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext), array('class' => 'helpdoclink'));
+ $module->help .= html_writer::tag('div', $OUTPUT->doc_link($link, $linktext, true), array('class' => 'helpdoclink'));
}
}
$module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
$course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true));
$oldsections = array();
$sections = array();
- foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) {
+ foreach ($DB->get_records('course_sections', array('course'=>$course->id), 'id') as $section) {
$oldsections[$section->section] = $section->id;
$sections[$section->id] = $section->section;
}
// Check that the course has been duplicated.
$this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
- gc_collect_cycles();
}
}
$marker = optional_param('marker',-1 , PARAM_INT);
$switchrole = optional_param('switchrole',-1, PARAM_INT);
$modchooser = optional_param('modchooser', -1, PARAM_BOOL);
+ $return = optional_param('return', 0, PARAM_LOCALURL);
$params = array();
if (!empty($name)) {
// Redirect to site root if Editing is toggled on frontpage
if ($course->id == SITEID) {
redirect($CFG->wwwroot .'/?redirect=0');
+ } else if (!empty($return)) {
+ redirect($CFG->wwwroot . $return);
} else {
$url = new moodle_url($PAGE->url, array('notifyeditingon' => 1));
redirect($url);
// Redirect to site root if Editing is toggled on frontpage
if ($course->id == SITEID) {
redirect($CFG->wwwroot .'/?redirect=0');
+ } else if (!empty($return)) {
+ redirect($CFG->wwwroot . $return);
} else {
redirect($PAGE->url);
}
var resources = Y.Node.create('<ul></ul>');
resources.addClass(CSS.SECTION);
sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
- // Define empty ul as droptarget, so that item could be moved to empty list
- var tar = new Y.DD.Drop({
- node: resources,
- groups: this.groups,
- padding: '20 0 20 0'
- });
}
+ // Define empty ul as droptarget, so that item could be moved to empty list
+ var tar = new Y.DD.Drop({
+ node: resources,
+ groups: this.groups,
+ padding: '20 0 20 0'
+ });
// Initialise each resource/activity in this section
this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY);
// Catch the page toggle
Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
-
- // Ensure that help links are opened in an appropriate popup
- this.container.all('div.helpdoclink a').on('click', function(e) {
- var anchor = e.target.ancestor('a', true);
-
- var args = {
- 'name' : 'popup',
- 'url' : anchor.getAttribute('href'),
- 'option' : ''
- };
- var options = [
- 'height=600',
- 'width=800',
- 'top=0',
- 'left=0',
- 'menubar=0',
- 'location=0',
- 'scrollbars',
- 'resizable',
- 'toolbar',
- 'status',
- 'directories=0',
- 'fullscreen=0',
- 'dependent'
- ]
- args.options = options.join(',');
-
- // Note: openpopup is provided by lib/javascript-static.js
- openpopup(e, args);
- });
},
/**
* Update any section areas within the scope of the specified
SECTIONIDPREFIX : 'section-',
SECTIONLI : 'li.section',
SHOW : 'a.editing_show',
- SHOWHIDE : 'a.editing_showhide'
+ SHOWHIDE : 'a.editing_showhide',
+ CONDITIONALHIDDEN : 'conditionalhidden',
+ AVAILABILITYINFODIV : 'div.availabilityinfo',
+ SHOWCLASS : 'editing_show',
+ ACCESSHIDECLASS : 'accesshide'
};
/**
var status = '';
var value;
- if (dimarea.hasClass(toggle_class)) {
+ if (button.hasClass(CSS.SHOWCLASS)) {
status = 'hide';
value = 1;
} else {
status = 'show';
value = 0;
}
-
- // Change the UI
- dimarea.toggleClass(toggle_class);
- // We need to toggle dimming on the description too
- element.all(CSS.CONTENTAFTERLINK).toggleClass(CSS.DIMMEDTEXT);
+ // Update button info.
var newstring = M.util.get_string(status, 'moodle');
hideicon.setAttrs({
'alt' : newstring,
button.set('title', newstring);
button.set('className', 'editing_'+status);
+ // If activity is conditionally hidden, then don't toggle.
+ if (!dimarea.hasClass(CSS.CONDITIONALHIDDEN)) {
+ // Change the UI.
+ dimarea.toggleClass(toggle_class);
+ // We need to toggle dimming on the description too.
+ element.all(CSS.CONTENTAFTERLINK).toggleClass(CSS.DIMMEDTEXT);
+ }
+ // Toggle availablity info for conditional activities.
+ var availabilityinfo = element.one(CSS.AVAILABILITYINFODIV);
+
+ if (availabilityinfo) {
+ availabilityinfo.toggleClass(CSS.ACCESSHIDECLASS);
+ }
return value;
},
/**
$manager = new course_enrolment_manager($PAGE, $course);
-$outcome = new stdClass;
+$outcome = new stdClass();
$outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
$outcome->error = '';
switch ($action) {
$user->fullname = fullname($user);
unset($user->id);
}
+ // Chrome will display users in the order of the array keys, so we need
+ // to ensure that the results ordered array keys. Fortunately, the JavaScript
+ // does not care what the array keys are. It uses user.id where necessary.
+ $outcome->response['users'] = array_values($outcome->response['users']);
$outcome->success = true;
break;
default:
// throw an exception if user is not able to assign the role in this context
$roles = get_assignable_roles($context, ROLENAME_SHORT);
- if (!key_exists($assignment['roleid'], $roles)) {
+ if (!array_key_exists($assignment['roleid'], $roles)) {
throw new invalid_parameter_exception('Can not assign roleid='.$assignment['roleid'].' in contextid='.$assignment['contextid']);
}
// throw an exception if user is not able to unassign the role in this context
$roles = get_assignable_roles($context, ROLENAME_SHORT);
- if (!key_exists($unassignment['roleid'], $roles)) {
+ if (!array_key_exists($unassignment['roleid'], $roles)) {
throw new invalid_parameter_exception('Can not unassign roleid='.$unassignment['roleid'].' in contextid='.$unassignment['contextid']);
}
$manager = new course_enrolment_manager($PAGE, $course);
-$outcome = new stdClass;
+$outcome = new stdClass();
$outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
$outcome->error = '';
switch ($action) {
}
$user->extrafields = implode(', ', $fieldvalues);
}
+ // Chrome will display users in the order of the array keys, so we need
+ // to ensure that the results ordered array keys. Fortunately, the JavaScript
+ // does not care what the array keys are. It uses user.id where necessary.
+ $outcome->response['users'] = array_values($outcome->response['users']);
$outcome->success = true;
break;
case 'enrol':
throw new enrol_ajax_exception('unknowajaxaction');
}
-echo json_encode($outcome);
\ No newline at end of file
+echo json_encode($outcome);
//throw an exception if user is not able to assign the role
$roles = get_assignable_roles($context);
- if (!key_exists($enrolment['roleid'], $roles)) {
+ if (!array_key_exists($enrolment['roleid'], $roles)) {
$errorparams = new stdClass();
$errorparams->roleid = $enrolment['roleid'];
$errorparams->courseid = $enrolment['courseid'];
navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id)));
// Create the user selector objects.
-$options = array('enrolid' => $enrolid);
+$options = array('enrolid' => $enrolid, 'accesscontext' => $context);
$potentialuserselector = new enrol_manual_potential_participant('addselect', $options);
$currentuserselector = new enrol_manual_current_participant('removeselect', $options);
.moodle-dialogue-base .moodle-dialogue-hd {font-size:110%;color:inherit;font-weight:bold;text-align:left;padding:5px 6px;margin:0;border-bottom:1px solid #ccc;background-color:#f6f6f6;}
.moodle-dialogue-base .closebutton {background-image:url(sprite.png);width:25px;height:15px;background-repeat:no-repeat;float:right;vertical-align:middle;display:inline-block;cursor:pointer;}
.moodle-dialogue-base .moodle-dialogue-bd {padding:5px; overflow: auto;}
-.moodle-dialogue-base .moodle-dialogue-fd {}
+.moodle-dialogue-base .moodle-dialogue-ft {}
.moodle-dialogue-confirm .confirmation-dialogue {text-align:center;}
.moodle-dialogue-confirm .confirmation-message {margin:0.5em 1em;}
HEADER : 'moodle-dialogue-hd',
BODY : 'moodle-dialogue-bd',
CONTENT : 'moodle-dialogue-content',
- FOOTER : 'moodle-dialogue-fd',
+ FOOTER : 'moodle-dialogue-ft',
HIDDEN : 'hidden',
LIGHTBOX : 'moodle-dialogue-lightbox'
};
.append(C('<div id="'+id+'" class="'+CSS.WRAP+'"></div>')
.append(C('<div class="'+CSS.HEADER+' yui3-widget-hd"></div>'))
.append(C('<div class="'+CSS.BODY+' yui3-widget-bd"></div>'))
- .append(C('<div class="'+CSS.CONTENT+' yui3-widget-ft"></div>')));
+ .append(C('<div class="'+CSS.FOOTER+' yui3-widget-ft"></div>')));
Y.one(document.body).append(config.notificationBase);
config.srcNode = '#'+id;
config.width = config.width || '400px';
$url->param('action', 'show');
- $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'iconsmall')));
+ $hideicon = $OUTPUT->action_icon($url, new pix_icon('t/'.$type, $tooltip, 'moodle', array('alt'=>$strshow, 'class'=>'smallicon')));
} else {
$url->param('action', 'hide');
$changedgrades = true;
} else if ($datatype === 'feedback') {
- if ($oldvalue->feedback === $postedvalue) {
+ if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
continue;
}
}
$string['pathssubdirroot'] = 'Пълен път до директорията на Moodle.';
$string['pathssubwwwroot'] = 'Пълен интернет адрес, на който ще се отваря Moodle. Не е възможно Moodle да се отваря чрез различни адреси. Ако Вашият сайт има няколко адреса трябва на всеки от другите адреси да направите пренасочване към този. Ако Вашият сайт се отваря както глобално от Интернет, така и от локална мрежа, настройте DNS, така че потребителите от локалната мрежа също да могат да ползват глобалния адрес. Ако адресът не е коректен, моля, променете адреса в браузъра си и започнете инсталирането с правилния адрес.';
$string['phpextension'] = '{$a} разширение на PHP';
+$string['phpversionhelp'] = '<p>Moodle изисква версия на PHP най-малко 4.3.0 или 5.1.0 (5.0.x има значителен брой известни проблеми).</p> <p>Вие използвате в момента версия {$a}</p> <p>Трябва да обновите PHP или да се преместите на нов хост (сървър) с по-нова версия на PHP!<br /> (В случая с 5.0.x може да опитате да инсталирате по-старата версия 4.4.x)</p>';
$string['wwwroot'] = 'Уеб адрес';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'English (fixes)';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'English for kids';
<p>Tämä saattaa aiheuttaa Moodlelle muistiongelmia myöhemmin, varsinkin jos sinulla on paljon mahdollisia moduuleita ja/tai paljon käyttäjiä.</p>
-<p>Suosittelemme, että valitset asetuksiksi PHP:n korkeimmalla mahdollisella raja-arvolla, esimerkiksi 16M.
+<p>Suosittelemme, että valitset asetuksiksi PHP:n korkeimmalla mahdollisella raja-arvolla, esimerkiksi 40M.
On olemassa monia tapoja joilla voit yrittää tehdä tämän:</p>
<ol>
<li>Jos pystyt, uudelleenkäännä PHP <i>--enable-memory-limit</i>. :llä.
Tämä sallii Moodlen asettaa muistirajan itse.</li>
-<li>Jos sinulla on pääsy php.ini tiedostoosi, voit muuttaa <b>memory_limit</b> asetuksen siellä johonkin kuten 16M. Jos sinulla ei ole pääsyoikeutta, voit kenties pyytää ylläpitäjää tekemään tämän puolestasi.</li>
+<li>Jos sinulla on pääsy php.ini tiedostoosi, voit muuttaa <b>memory_limit</b> asetuksen siellä johonkin kuten 40M. Jos sinulla ei ole pääsyoikeutta, voit kenties pyytää ylläpitäjää tekemään tämän puolestasi.</li>
<li>Joillain PHP palvelimilla voit luoda a .htaccess tiedoston Moodle hakemistossa, sisältäen tämän rivin:
-<p><blockquote>php_value memory_limit 16M</blockquote></p>
+<p><blockquote>php_value memory_limit 40M</blockquote></p>
<p>Kuitenkin, joillain palvelimilla tämä estää <b>kaikkia</b> PHP sivuja toimimasta (näet virheet, kun katsot sivuja), joten sinun täytyy poistaa .htaccess tiedosto.</p></li>
</ol>';
$string['paths'] = 'Polut';
$string['cannotcreatelangdir'] = 'לא ניתן ליצור סיפריית שפה.';
$string['cannotcreatetempdir'] = 'לא ניתן ליצור סיפרייה זמנית.';
$string['cannotdownloadcomponents'] = 'לא ניתן להוריד רכיבים.';
-$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ ZIP.';
+$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ 7Zip';
$string['cannotfindcomponent'] = 'הרכיב לא נמצא.';
$string['cannotsavemd5file'] = 'לא ניתן לשמור קובץ md5.';
$string['cannotsavezipfile'] = 'לא ניתן לשמור קובץ ZIP.';
$string['cannotunzipfile'] = 'לא ניתן לפתוח את קובץ ה-ZIP.';
$string['componentisuptodate'] = 'הרכיב מעודכן.';
-$string['downloadedfilecheckfailed'] = '× ×\9bש×\9c×\94 ×\91×\93×\99קת ×\94×§×\95×\91×¥ ×\94×\9e×\95ר×\93.';
+$string['downloadedfilecheckfailed'] = '×\94×§×\95×\91×¥ ×\90שר ×\99ר×\93 × ×\9eצ×\90 ש×\92×\95×\99';
$string['invalidmd5'] = 'md5 לא חוקי';
$string['missingrequiredfield'] = 'חסר שדה נדרש כלשהו';
$string['remotedownloaderror'] = 'הורדת הרכיב לשרת שלך כשלה, אנא וודא את הגדרות ה-proxy שלך. תוספת PHP cURL מומלצת מאוד להתקנה.
$string['welcomep50'] = 'השימוש בכל היישומים בחבילה זו מפוקח ע"י הרשיונות המתאימים להם. החבילה
<strong>{$a->installername}</strong>
השלמה היא
-<a href="http://www.opensource.org/docs/definition_plain.html"> קוד פתוח
-</a>
-והיא מבוזרת תחת רישיון
-<a>
-href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
+<a href="http://www.opensource.org/docs/definition_plain.html">קוד פתוח</a>
+והיא מופצת תחת רשיון
+<a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
$string['welcomep60'] = 'העמודים הבאים יובילו אותך בצורה פשוטה דרך כמה צעדים לעיצוב הגדרות <strong>Moodle</strong> במחשבך.
תוכל לאשר את הגדרות ברירת המחדל או, באפשרותך, לשנותם לפי צרכיך.';
$string['welcomep70'] = 'הקש על לחצן ה"המשך" למטה כדי להמשיך עם הגדרת ה-<strong>Moodle</strong>';
defined('MOODLE_INTERNAL') || die();
+$string['parentlanguage'] = '';
$string['thisdirection'] = 'ltr';
$string['thislanguage'] = 'Italiano';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'ja';
+$string['thisdirection'] = 'ltr';
+$string['thislanguage'] = '日本語 小学生';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['clianswerno'] = 't';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueerror'] = 'Ralat, nilai tidak betul "{$a->value}" untuk "{$a->option}"';
+$string['cliincorrectvalueretry'] = 'Nilai yang salah, sila cuba lagi';
+$string['clitypevalue'] = 'taip nilai';
+$string['clitypevaluedefault'] = 'taip nilai, tekan Enter untuk gunakan nilai lalai ({$a})';
+$string['cliunknowoption'] = 'Pilihan yang tidak diketahui:
+ {$a}
+Sila gunakan pilihan --help';
+$string['cliyesnoprompt'] = 'tapi y (ya) atau t (tidak)';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['admindirname'] = 'Direktori admin';
+$string['availablelangs'] = 'Senarai bahasa yang tersedia';
+$string['chooselanguagehead'] = 'Pilih bahasa';
+$string['chooselanguagesub'] = 'Sila pilih bahasa untuk pemasangan. Bahasa ini juga akan digunakan sebagai bahasa lalai untuk laman, ia boleh diubah kemudian.';
+$string['clialreadyinstalled'] = 'config.php fail sudah wujud, sila gunakan admin/cli/upgrade.php jika anda mahu menaik taraf laman web anda.';
+$string['cliinstallheader'] = 'Baris arahan pemasangan program Moodle {$a}';
+$string['databasehost'] = 'Hos pangkalan data';
+$string['databasename'] = 'Nama pangkalan data';
+$string['databasetypehead'] = 'Pilih pemacu pangkalan data';
+$string['dataroot'] = 'Direktori data';
+$string['dbprefix'] = 'Awalan jadual';
+$string['dirroot'] = 'Direktori Moodle';
+$string['environmenthead'] = 'Memeriksa persekitaran anda ...';
+$string['environmentsub2'] = 'Setiap pelepasan Moodle mempunyai keperluan minimum versi PHP dan beberapa sambungan mandatori PHP. Persekitaran penuh disemak sebelum setiap pemasangan dan naik taraf. Sila hubungi pentadbir pelayan jika anda tidak tahu bagaimana untuk memasang versi baru atau membolehkan sambungan PHP.';
+$string['errorsinenvironment'] = 'Semakan persekitaran gagal!';
+$string['installation'] = 'Pemasangan';
+$string['langdownloaderror'] = 'Malangnya bahasa "{$a}" tidak boleh dimuat turun. Proses pemasangan akan diteruskan dalam bahasa Bahasa Inggeris.';
+$string['memorylimithelp'] = '<p> Had memori PHP untuk pelayan anda ditetapkan kepada {$a}. </p>
+
+<p> Hal ini akan menyebabkan Moodle untuk mendapat masalah memori di kemudian hari, terutama jika anda mempunyai banyak modul yang diaktifkan dan/atau ramai pengguna. </p>
+
+<p> Kami menyarankan anda mengkonfigurasikan PHP dengan had yang lebih tinggi jika memungkinkan, seperti 40M. Ada beberapa cara untuk melakukan hal ini yang anda boleh cuba: </p>
+<ol>
+<li> Jika anda mampu, kompil semula PHP dengan <i>--enable-memory-limit.</i> Hal ini akan membolehkan Moodle untuk menetapkan batas memori itu sendiri. </li>
+<li> Jika anda mempunyai akses ke fail php.ini, anda boleh menukar setting <b>memory_limit</b> di sana untuk sesuatu seperti 40M. Jika anda tidak mempunyai akses anda mungkin boleh meminta pentadbir anda untuk melakukan ini untuk anda. </li>
+<li> Pada beberapa server PHP anda boleh mencipta baris fail .htaccess di direktori Moodle mengandungi ini: <blockquote><div> php_value memory_limit 40M </div></blockquote><p> Namun, pada beberapa server ini akan mencegah <b>semua</b> laman PHP dari berjalan (anda akan melihat ralat ketika anda melihat halaman), sehingga anda hapuskan file .htaccess. </p></li></ol>';
+$string['paths'] = 'Laluan';
+$string['pathserrcreatedataroot'] = 'Direktori data ({$a->dataroot}) tidak boleh diwujudkan oleh pemasang.';
+$string['pathshead'] = 'Sahkan laluan';
+$string['pathsrodataroot'] = 'Direktori dataroot tidak dapat ditulis.';
+$string['pathsroparentdataroot'] = 'Direktori induk ({$a->parent}) tidak boleh tulis. Direktori data ({$a->dataroot}) tidak boleh diwujudkan oleh pemasang.';
+$string['pathssubadmindir'] = 'Beberapa webhos menggunakan /admin sebagai URL khas untuk anda akses panel kawalan atau sesuatu yang lain. Malangnya, ini bertentangan dengan lokasi standard untuk halaman pentadbiran Moodle. Anda boleh memperbaiki ini dengan menamakan semula direktori admin dalam pemasangan anda, dan meletakkan nama baru di sini. Sebagai contoh: <br /> <br /> <b> moodleadmin </ b> <br /> <br />
+Ini akan memulihkan pautan admin dalam Moodle.';
+$string['pathssubdataroot'] = 'Anda perlukan lokasi di mana Moodle boleh menyimpan fail yang dimuat naik. Direktori ini sepatutnya boleh dibaca DAN BOLEH DITULIS oleh pengguna web server (biasanya \'nobody\' atau \'apache\'), tetapi ia mestilah tidak boleh diakses secara langsung melalui laman web. Pemasang akan cuba untuk mewujudkannya jika belum ada.';
+$string['pathssubdirroot'] = 'Direktori laluan penuh untuk pemasangan Moodle.';
+$string['pathssubwwwroot'] = 'Alamat penuh web di mana Moodle akan dicapai. Adalah tidak mungkin untuk mengakses Moodle menggunakan pelbagai alamat. Jika laman anda mempunyai beberapa alamat awam, anda mesti menubuhkan pelencongan kekal kepada semua mereka kecuali yang satu ini. Jika laman web anda boleh diakses kedua-duanya dari Intranet dan Internet menggunakan alamat awam di sini dan menubuhkan DNS supaya pengguna Intranet boleh menggunakan alamat awam juga. Jika alamat itu tidak betul, sila ubah URL di pelayar anda untuk memulakan semula pemasangan dengan nilai yang berbeza.';
+$string['pathsunsecuredataroot'] = 'Lokasi dataroot tidak selamat';
+$string['pathswrongadmindir'] = 'Direktori admin tidak wujud';
+$string['phpextension'] = 'Sambungan PHP {$a}';
+$string['phpversion'] = 'Versi PHP';
+$string['phpversionhelp'] = '<p> Moodle memerlukan versi PHP minimal 4.3.0 atau 5.1.0 (5.0.x memiliki sejumlah masalah yang diketahui). </p>
+<p> Anda sedang menjalankan versi {$a} </p>
+<p> Anda harus upgrade PHP atau berpindah ke host dengan versi terbaru PHP! <br /> (Dalam kes 5.0.x Anda juga boleh turun taraf ke versi 4.4.x) </p>';
+$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
+$string['welcomep20'] = 'Anda melihat halaman ini kerana anda telah berjaya memasang dan melancarkan pakej <strong>{$a->packname} {$a->packversion}</strong> di komputer anda. Tahniah!';
+$string['welcomep30'] = 'Keluaran ini <strong>{$a->installername}</strong> termasuk aplikasi untuk mencipta sebuah persekitaran di mana <strong>Moodle</strong> akan beroperasi, iaitu:';
+$string['welcomep40'] = 'Pakej ini juga termasuk <strong>Moodle {$a->moodlerelease} ({$a->moodleversion})</strong>.';
+$string['welcomep50'] = 'Penggunaan semua aplikasi di dalam pakej ini dikawal oleh lesen masing-masing. Pakej lengkap <strong>{$a->installername}</strong> adalah <a href="http://www.opensource.org/docs/definition_plain.html">sumber terbuka</a> dan diedarkan di bawah lesen <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
+$string['welcomep60'] = 'Laman-laman berikut akan membawa anda melalui beberapa langkah-langkah mudah diikuti untuk mengkonfigurasi dan menetapkan <strong>Moodle</strong> pada komputer anda. Anda mungkin menerima tetapan lalai atau, dengan pilihan, meminda untuk disesuaikan dengan keperluan anda.';
+$string['welcomep70'] = 'Klik butang "Seterusnya" di bawah untuk meneruskan penubuhan <strong>Moodle</strong>.';
+$string['wwwroot'] = 'Alamat Web';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Bahasa';
+$string['next'] = 'Seterusnya';
+$string['previous'] = 'Sebelum';
defined('MOODLE_INTERNAL') || die();
-$string['admindirname'] = 'Admin Directory';
+$string['admindirname'] = 'Director Admin';
$string['availablelangs'] = 'Pachete de limbă disponibile';
$string['chooselanguagehead'] = 'Selectare limbă';
$string['chooselanguagesub'] = 'Vă rugăm selectaţi limba pentru interfaţa de instalare, limba selectată va fi folosită EXCLUSIV în cadrul procedurii de instalare. Ulterior veţi putea selecta limba în care doriţi să fie afişată interfaţa.';
-$string['dataroot'] = 'Data Directory';
+$string['databasehost'] = 'Gazdă baza de date';
+$string['databasename'] = 'Nume baza de date';
+$string['databasetypehead'] = 'Alegere driver baza de date';
+$string['dataroot'] = 'Director date';
+$string['datarootpermission'] = 'Permisiuni directoare date';
$string['dbprefix'] = 'Prefix tabele';
$string['dirroot'] = 'Director Moodle';
$string['environmenthead'] = 'Se verifică mediul...';
$string['installation'] = 'Instalare';
+$string['paths'] = 'Căi';
+$string['pathshead'] = 'Confirmare căi';
+$string['phpextension'] = 'extensie PHP {$a}';
$string['phpversion'] = 'Versiune PHP';
$string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
$string['wwwroot'] = 'Adresă Web';
$string['dbprefix'] = 'Префикс табеле';
$string['dirroot'] = 'Moodle директоријум';
$string['environmenthead'] = 'Проверавање Вашег окружења...';
-$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верѕије и неколико обавезних PHP екстензија.
+$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верзије и неколико обавезних PHP екстензија.
Пуна провера окружења се врши пре сваке инсталације или ажурирања постојеће верзије. Уколико не знате како да инсталирате нову верзију или омогућите PHP ектензије контактирајте Вашег сервер администратора.';
$string['errorsinenvironment'] = 'Провера окружења није прошла!';
$string['installation'] = 'Инсталација';
Ако је адреса нетачна промените URL у свом веб читачу да бисте поново покренули инсталацију са другачијом вредношћу.';
$string['pathsunsecuredataroot'] = 'Dataroot локација није безбедна';
$string['pathswrongadmindir'] = 'Админ директоријум не постоји';
-$string['phpextension'] = '{$a} PHP екстенѕија';
+$string['phpextension'] = '{$a} PHP екстензија';
$string['phpversion'] = 'PHP верзија';
$string['phpversionhelp'] = '<p>Moodle захтева најмање PHP верзију 4.3.0 или 5.1.0 (5.0.x има бројне уочене проблеме).</p>
<p>Тренутно користите верзију {$a}</p>
defined('MOODLE_INTERNAL') || die();
+$string['clianswerno'] = 'n';
+$string['cliansweryes'] = 'y';
+$string['cliincorrectvalueerror'] = '錯誤,不正確的值 "{$a->value}" 用於 "{$a->option}"';
+$string['cliincorrectvalueretry'] = '不正確的值,請再試一次';
+$string['clitypevalue'] = '輸入值';
+$string['clitypevaluedefault'] = '輸入值,按Enter可使用預設值({$a})';
+$string['cliunknowoption'] = '不認得的選項: {$a}
+請使用 --幫助 選項。';
+$string['cliyesnoprompt'] = '輸入y(是) 或n(否)';
$string['environmentrequireinstall'] = '必須安裝/啟用';
$string['environmentrequireversion'] = '要求版本為 {$a->needed} ,您目前版本為 {$a->current}';
$string['cannotsavezipfile'] = '無法儲存 ZIP 檔案。';
$string['cannotunzipfile'] = '無法解壓縮檔案。';
$string['componentisuptodate'] = '元件已經是最新的了。';
-$string['downloadedfilecheckfailed'] = '下載檔案檢查錯誤。';
-$string['invalidmd5'] = '無效的 md5';
+$string['downloadedfilecheckfailed'] = '下載的檔案檢查失敗';
+$string['invalidmd5'] = '這檢查變項是錯的,再試一次。';
$string['missingrequiredfield'] = '缺少部份必填欄位';
$string['remotedownloaderror'] = '下載元件至伺服器失敗,檢查代理伺服器的設定、高度建議安裝PHP cURL,您必須手動下載<a href="{$a->url}">{$a->url}</a>,並且複製到伺服器"{$a->dest}" 解壓縮';
$string['wrongdestpath'] = '錯誤的目的路徑。';
-$string['wrongsourcebase'] = '錯誤的來源網址基礎。';
+$string['wrongsourcebase'] = '錯誤的來源基礎網址。';
$string['wrongzipfilename'] = '錯誤的 ZIP 檔名。';
$string['admindirname'] = '管理目錄';
$string['availablelangs'] = '可使用的語言包';
$string['chooselanguagehead'] = '選擇一種語言';
-$string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。稍後您可以根據需要重新選擇用於網站和使用者的語言。';
+$string['chooselanguagesub'] = '請選擇在安裝過程中使用的語言。這語言將成為此網站預設的語言。稍後您可以根據需要重新選擇。';
+$string['clialreadyconfigured'] = '檔案 config.php 已經存在,若你要安裝這一網站,請使用dmin/cli/install_database.php';
+$string['clialreadyinstalled'] = '檔案 config.php 已經存在,若你要升級這一網站,請使用admin/cli/upgrade.php';
+$string['cliinstallheader'] = 'Moodle {$a} 命令列安裝程式';
+$string['databasehost'] = '資料庫主機';
+$string['databasename'] = '資料庫名稱';
+$string['databasetypehead'] = '選擇資料庫裝置';
$string['dataroot'] = '資料目錄';
+$string['datarootpermission'] = '資料目錄存取授權';
$string['dbprefix'] = '資料表名稱的前置字元';
$string['dirroot'] = 'Moodle目錄';
$string['environmenthead'] = '檢查您的環境中...';
+$string['environmentsub2'] = '每一個Moodle版本都有一些PHP版本的最低要求和一堆強制開啟的PHP擴展。在進行安裝或升級之前都需要作完整的環境檢查。<br />
+若你不知道要怎樣新的PHP版本或啟用PHP擴展,請聯絡伺服器管理員。';
+$string['errorsinenvironment'] = '環境檢查失敗!';
$string['installation'] = '安裝';
$string['langdownloaderror'] = '很不幸地,語言“{$a}”並未安裝。安裝過程將以英文繼續。';
$string['memorylimithelp'] = '<p>PHP記憶體上限目前設定為{$a}。</p>
<p>建議您儘可能將PHP的上限設得高一點,比如16M。
以下有幾種方式您可以試試:
<ol>
-<li>如果可以的話,用<i>--enable-memory-limit</i>重新編譯PHP。讓Moodle自己設定記憶體上限.
-<li>如果您要使用php.ini檔, 您可以改變<b>memory_limit</b>這個設定值,例如到16M。如果您無法使用這個檔,您可以請您的管理者幫您做
-<li>在一些PHP伺服器上,您可以在Moodle目錄下,建立.htaccess檔,包含這行:<p><blockquote>php_value memory_limit 16M</blockquote></p>
+<li>如果可以的話,用<i>--enable-memory-limit</i>重新編譯PHP。讓 Moodle 自己設定記憶體上限。
+<li>如果您要使用 php.ini 檔,您可以改變<b>memory_limit</b>這個設定值,例如到16M。如果您無法使用這個檔,您可以請您的管理者幫您做
+<li>在一些PHP伺服器上,您可以在Moodle目錄下,建立 .htaccess 檔,包含這行:<p><blockquote>php_value memory_limit 16M</blockquote></p>
<p>然而,在一些伺服器上,這將造成<b>所有的</b> PHP 網頁無法運作(當您看這些網頁時,您就會看到錯誤) 因此,您就必須將 .htaccess 檔案移除。
</ol>';
+$string['paths'] = '路徑';
+$string['pathserrcreatedataroot'] = '資料目錄 ({$a->dataroot})無法由這安裝程式建立';
+$string['pathshead'] = '確認路徑';
+$string['pathsrodataroot'] = '資料根目錄是無法寫入的';
+$string['pathsroparentdataroot'] = '上層目錄({$a->parent})是不可寫入的。安裝程式無法建立資料目錄({$a->dataroot})。';
+$string['pathssubadmindir'] = '有些網站主機使用/admin這個網址來瀏覽控制面版或其他功能。很不幸,這個設定和Moodle管理頁面的標準路徑產生衝突。這個問題可以解決,只需在您的安裝目錄中把admin更換名稱,然後把新名稱輸入到這裡。例如<em>moodleadmin</em>這麼做會改變Moodle中的管理連接。';
+$string['pathssubdataroot'] = '你需要有一個地方讓Moodle可以儲存上傳的檔案。這一目錄對於網頁伺服器用戶(通常是"nobody"或"apache")而言,應該是可讀的和<b>可寫的</b>。但是它必須不能經由網頁直接存取。若此目錄不存在,這安裝程式將會試著建立它。';
+$string['pathssubdirroot'] = 'Moodle安裝的完整目錄路徑。';
+$string['pathssubwwwroot'] = '可以瀏覽到Moodle的完整網址。Moodle不支援透過多個網址瀏覽,如果您的往佔有多個公開網址,您必須把這個網址以外的網址都設定為永久重新導向。如果您的網站可以透過內部網址瀏覽,有可以透過這個公開網址瀏覽,那麼請設定DNS內部使網路使用者也能使用的空該網址。如果此網址不正確,請在瀏覽器中修改URL來重新安裝,並設定另一個網址。';
+$string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全';
+$string['pathswrongadmindir'] = '管理目錄不存在';
+$string['phpextension'] = '{$a} PHP擴展';
$string['phpversion'] = 'PHP版本';
$string['phpversionhelp'] = '<p>Moodle 需要至少4.1.0.的PHP版本 </p>
<p>您目前執行的是{$a} 版</p>
$string['configmymoodleredirect'] = 'This setting forces redirects to /my on login for non-admins and replaces the top level site navigation with /my';
$string['configmypagelocked'] = 'This setting prevents the default page from being edited by any non-admins';
$string['confignavcourselimit'] = 'Limits the number of courses shown to the user when they are either not logged in or are not enrolled in any courses.';
-$string['confignavshowallcourses'] = 'If enabled users will see courses they are enrolled in both within the My Courses branch and the course structure. When disabled users with enrolments will only see the My Courses branch of the navigaiton.';
+$string['confignavshowallcourses'] = 'If enabled users will see courses they are enrolled in both within the My Courses branch and the course structure. When disabled users with enrolments will only see the My Courses branch of the navigaiton. The number of course shown would still be limited by "Course limit(navcourselimit)" setting when user is either not logged in or not enrolled in any course.';
$string['confignavshowcategories'] = 'Show course categories in the navigation bar and navigation blocks. This does not occur with courses the user is currently enrolled in, they will still be listed under mycourses without categories.';
$string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out. Who should see these notifications?';
$string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
$string['addfields'] = 'Add {$a} fields to form';
$string['advancedelement'] = 'Advanced element';
+$string['close'] = 'Close';
$string['day'] = 'Day';
$string['display'] = 'Display';
$string['err_alphanumeric'] = 'You must enter only letters or numbers here.';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] = 'Excel spreadsheet';
$string['application/vnd.openxmlformats-officedocument.spreadsheetml.template'] = 'Excel template';
$string['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] = 'Word document';
+$string['application/epub_zip'] = 'EPUB ebook';
$string['archive'] = 'Archive ({$a->EXT})';
$string['audio'] = 'Audio file ({$a->EXT})';
$string['default'] = '{$a->mimetype}';
$string['course:enrolconfig'] = 'Configure enrol instances in courses';
$string['course:enrolreview'] = 'Review course enrolments';
$string['course:ignorefilesizelimits'] = 'Use files larger than any file size restrictions';
+$string['course:isincompletionreports'] = 'Be shown on completion reports';
$string['course:manageactivities'] = 'Manage activities';
$string['course:managefiles'] = 'Manage files';
$string['course:managegrades'] = 'Manage grades';
array(array('id' => $token->userid)), $token->serviceid);
if (!is_siteadmin($token->userid) and
- key_exists($token->userid, $usermissingcaps)) {
+ array_key_exists($token->userid, $usermissingcaps)) {
$missingcapabilities = implode(', ',
$usermissingcaps[$token->userid]);
if (!empty($missingcapabilities)) {
*/
class Bennu {
- function timestamp_to_datetime($t = NULL) {
+ static function timestamp_to_datetime($t = NULL) {
if($t === NULL) {
$t = time();
}
return gmstrftime('%Y%m%dT%H%M%SZ', $t);
}
- function generate_guid() {
+ static function generate_guid() {
// Implemented as per the Network Working Group draft on UUIDs and GUIDs
// These two octets get special treatment
*/
class iCalendar_parameter {
- function multiple_values_allowed($parameter) {
+ static function multiple_values_allowed($parameter) {
switch($parameter) {
case 'DELEGATED-FROM':
case 'DELEGATED-TO':
}
}
- function default_value($parameter) {
+ static function default_value($parameter) {
switch($parameter) {
case 'CUTYPE': return 'INDIVIDUAL';
case 'FBTYPE': return 'BUSY';
}
}
- function is_valid_value(&$parent_property, $parameter, $value) {
+ static function is_valid_value(&$parent_property, $parameter, $value) {
switch($parameter) {
// These must all be a URI
case 'ALTREP':
}
}
- function do_value_formatting($parameter, $value) {
+ static function do_value_formatting($parameter, $value) {
switch($parameter) {
// Parameters of type CAL-ADDRESS or URI MUST be double-quoted
case 'ALTREP':
}
}
- function undo_value_formatting($parameter, $value) {
+ static function undo_value_formatting($parameter, $value) {
}
}
* @return bool True if all of the blocks within that region are docked
*/
public function region_completely_docked($region, $output) {
- if (!$this->page->theme->enable_dock) {
+ global $CFG;
+ // If theme doesn't allow docking or allowblockstodock is not set, then return.
+ if (!$this->page->theme->enable_dock || empty($CFG->allowblockstodock)) {
return false;
}
global $DB;
list($enrolledsql, $params) = get_enrolled_sql(
- context_course::instance($this->course->id), '', $groupid, true);
+ context_course::instance($this->course->id),
+ 'moodle/course:isincompletionreports', $groupid, true);
$sql = 'SELECT u.id, u.firstname, u.lastname, u.idnumber';
if ($extracontext) {
)
),
+ 'moodle/course:isincompletionreports' => array(
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_COURSE,
+ 'archetypes' => array(
+ 'student' => CAP_ALLOW,
+ ),
+ ),
+
'moodle/course:viewscales' => array(
'captype' => 'read',
upgrade_main_savepoint(true, 2012062502.03);
}
+ if ($oldversion < 2012062502.07) {
+ // Find all orphaned blog associations that might exist.
+ $sql = "SELECT ba.id
+ FROM {blog_association} ba
+ LEFT JOIN {post} p
+ ON p.id = ba.blogid
+ WHERE p.id IS NULL";
+ $orphanedrecordids = $DB->get_records_sql($sql);
+ // Now delete these associations.
+ foreach ($orphanedrecordids as $orphanedrecord) {
+ $DB->delete_records('blog_association', array('id' => $orphanedrecord->id));
+ }
+
+ upgrade_main_savepoint(true, 2012062502.07);
+ }
+
return true;
}
$participants->close();
// now clean up all remainders that were not removed correctly
- $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name));
+ $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$name));
$DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
// finally drop the enrol row
private function get_file_info_context_module($context, $component, $filearea, $itemid, $filepath, $filename) {
global $COURSE, $DB, $CFG;
+ static $cachedmodules = array();
- if (!$cm = get_coursemodule_from_id('', $context->instanceid)) {
+ if (!array_key_exists($context->instanceid, $cachedmodules)) {
+ $cachedmodules[$context->instanceid] = get_coursemodule_from_id('', $context->instanceid);
+ }
+
+ if (!($cm = $cachedmodules[$context->instanceid])) {
return null;
}
*/
public abstract function get_children();
+ /**
+ * Builds SQL sub query (WHERE clause) for selecting files with the specified extensions
+ *
+ * If $extensions == '*' (any file), the result is array('', array())
+ * otherwise the result is something like array('AND filename ...', array(...))
+ *
+ * @param string|array $extensions - either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param string $prefix prefix for DB table files in the query (empty by default)
+ * @return array of two elements: $sql - sql where clause and $params - array of parameters
+ */
+ protected function build_search_files_sql($extensions, $prefix = null) {
+ global $DB;
+ if (strlen($prefix)) {
+ $prefix = $prefix.'.';
+ } else {
+ $prefix = '';
+ }
+ $sql = '';
+ $params = array();
+ if (is_array($extensions) && !in_array('*', $extensions)) {
+ $likes = array();
+ $cnt = 0;
+ foreach ($extensions as $ext) {
+ $cnt++;
+ $likes[] = $DB->sql_like($prefix.'filename', ':filename'.$cnt, false);
+ $params['filename'.$cnt] = '%'.$ext;
+ }
+ $sql .= ' AND (' . join(' OR ', $likes) . ')';
+ }
+ return array($sql, $params);
+ }
+
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * It is recommended to overwrite this function so it uses a proper SQL
+ * query and does not create unnecessary file_info objects (might require a lot of time
+ * and memory usage on big sites).
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ $list = $this->get_children();
+ $nonemptylist = array();
+ foreach ($list as $fileinfo) {
+ if ($fileinfo->is_directory()) {
+ if ($fileinfo->count_non_empty_children($extensions)) {
+ $nonemptylist[] = $fileinfo;
+ }
+ } else if ($extensions === '*') {
+ $nonemptylist[] = $fileinfo;
+ } else {
+ $filename = $fileinfo->get_visible_name();
+ $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+ if (!empty($extension) && in_array('.' . $extension, $extensions)) {
+ $nonemptylist[] = $fileinfo;
+ }
+ }
+ }
+ return $nonemptylist;
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * We usually don't need the exact number of non empty children if it is >=2 (see param $limit)
+ * This function is used by repository_local to evaluate if the folder is empty. But
+ * it also can be used to check if folder has only one subfolder because in some cases
+ * this subfolder can be skipped.
+ *
+ * It is strongly recommended to overwrite this function so it uses a proper SQL
+ * query and does not create file_info objects (later might require a lot of time
+ * and memory usage on big sites).
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ $list = $this->get_children();
+ $cnt = 0;
+ // first loop through files
+ foreach ($list as $fileinfo) {
+ if (!$fileinfo->is_directory()) {
+ if ($extensions !== '*') {
+ $filename = $fileinfo->get_visible_name();
+ $extension = textlib::strtolower(pathinfo($filename, PATHINFO_EXTENSION));
+ if (empty($extension) || !in_array('.' . $extension, $extensions)) {
+ continue;
+ }
+ }
+ if ((++$cnt) >= $limit) {
+ return $cnt;
+ }
+ }
+ }
+ // now loop through directories
+ foreach ($list as $fileinfo) {
+ if ($fileinfo->is_directory() && $fileinfo->count_non_empty_children($extensions)) {
+ if ((++$cnt) >= $limit) {
+ return $cnt;
+ }
+ }
+ }
+ return $cnt;
+ }
+
/**
* Returns parent file_info instance
*
public function get_params_rawencoded() {
$params = $this->get_params();
$encoded = array();
- $encoded[] = 'contextid='.$params['contextid'];
- $encoded[] = 'component='.$params['component'];
- $encoded[] = 'filearea='.$params['filearea'];
- $encoded[] = 'itemid='.(is_null($params['itemid']) ? -1 : $params['itemid']);
- $encoded[] = 'filepath='.(is_null($params['filepath']) ? '' : rawurlencode($params['filepath']));
- $encoded[] = 'filename='.((is_null($params['filename']) or $params['filename'] === '.') ? '' : rawurlencode($params['filename']));
+ $encoded[] = 'contextid=' . $params['contextid'];
+ $encoded[] = 'component=' . $params['component'];
+ $encoded[] = 'filearea=' . $params['filearea'];
+ $encoded[] = 'itemid=' . (is_null($params['itemid']) ? -1 : $params['itemid']);
+ $encoded[] = 'filepath=' . (is_null($params['filepath']) ? '' : rawurlencode($params['filepath']));
+ $encoded[] = 'filename=' . ((is_null($params['filename']) or $params['filename'] === '.') ? '' : rawurlencode($params['filename']));
return $encoded;
}
* @return array of file_info instances
*/
public function get_children() {
- $children = array();
+ return $this->get_filtered_children('*', false, true);
+ }
- if ($child = $this->get_area_course_summary(0, '/', '.')) {
- $children[] = $child;
- }
- if ($child = $this->get_area_course_section(null, null, null)) {
- $children[] = $child;
- }
- if ($child = $this->get_area_backup_section(null, null, null)) {
- $children[] = $child;
- }
- if ($child = $this->get_area_backup_course(0, '/', '.')) {
- $children[] = $child;
- }
- if ($child = $this->get_area_backup_automated(0, '/', '.')) {
- $children[] = $child;
- }
- if ($child = $this->get_area_course_legacy(0, '/', '.')) {
- $children[] = $child;
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+ $areas = array(
+ array('course', 'summary'),
+ array('course', 'section'),
+ array('backup', 'section'),
+ array('backup', 'course'),
+ array('backup', 'automated'),
+ array('course', 'legacy')
+ );
+ $children = array();
+ foreach ($areas as $area) {
+ if ($child = $this->get_file_info($area[0], $area[1], 0, '/', '.')) {
+ if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+ $children[] = $child;
+ if (($countonly !== false) && count($children) >= $countonly) {
+ return $countonly;
+ }
+ }
+ }
}
if (!has_capability('moodle/course:managefiles', $this->context)) {
// 'managefiles' capability is checked in every activity module callback.
// Don't even waste time on retrieving the modules if we can't browse the files anyway
- return $children;
- }
-
- // now list all modules
- $modinfo = get_fast_modinfo($this->course);
- foreach ($modinfo->cms as $cminfo) {
- if (empty($cminfo->uservisible)) {
- continue;
- }
- $modcontext = get_context_instance(CONTEXT_MODULE, $cminfo->id);
- if ($child = $this->browser->get_file_info($modcontext)) {
- $children[] = $child;
+ } else {
+ // now list all modules
+ $modinfo = get_fast_modinfo($this->course);
+ foreach ($modinfo->cms as $cminfo) {
+ if (empty($cminfo->uservisible)) {
+ continue;
+ }
+ $modcontext = context_module::instance($cminfo->id, IGNORE_MISSING);
+ if ($child = $this->browser->get_file_info($modcontext)) {
+ if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+ $children[] = $child;
+ if (($countonly !== false) && count($children) >= $countonly) {
+ return $countonly;
+ }
+ }
+ }
}
}
+ if ($countonly !== false) {
+ return count($children);
+ }
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
*
return $result;
}
+
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ if (!$this->lf->is_directory()) {
+ return array();
+ }
+
+ $result = array();
+ $fs = get_file_storage();
+
+ $storedfiles = $fs->get_directory_files($this->context->id, 'course', 'legacy', 0,
+ $this->lf->get_filepath(), false, true, "filepath, filename");
+ foreach ($storedfiles as $file) {
+ $extension = textlib::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+ if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
+ $fileinfo = new file_info_area_course_legacy($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
+ $this->itemidused, $this->readaccess, $this->writeaccess, false);
+ if (!$file->is_directory() || $fileinfo->count_non_empty_children($extensions)) {
+ $result[] = $fileinfo;
+ }
+ }
+ }
+
+ return $result;
+ }
}
/**
return $children;
}
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ global $DB;
+ $params1 = array(
+ 'courseid' => $this->course->id,
+ 'contextid' => $this->context->id,
+ 'component' => 'course',
+ 'filearea' => 'section',
+ 'emptyfilename' => '.');
+ $sql1 = "SELECT DISTINCT cs.id FROM {files} f, {course_sections} cs
+ WHERE cs.course = :courseid
+ AND f.contextid = :contextid
+ AND f.component = :component
+ AND f.filearea = :filearea
+ AND f.itemid = cs.id
+ AND f.filename <> :emptyfilename";
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
+ $cnt = 0;
+ foreach ($rs as $record) {
+ if ((++$cnt) >= $limit) {
+ break;
+ }
+ }
+ $rs->close();
+ return $cnt;
+ }
+
/**
* Returns parent file_info instance
*
return $children;
}
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ global $DB;
+ $params1 = array(
+ 'courseid' => $this->course->id,
+ 'contextid' => $this->context->id,
+ 'component' => 'backup',
+ 'filearea' => 'section',
+ 'emptyfilename' => '.');
+ $sql1 = "SELECT DISTINCT cs.id sectionid FROM {files} f, {course_sections} cs
+ WHERE cs.course = :courseid
+ AND f.contextid = :contextid
+ AND f.component = :component
+ AND f.filearea = :filearea
+ AND f.itemid = cs.id
+ AND f.filename <> :emptyfilename";
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
+ $cnt = 0;
+ foreach ($rs as $record) {
+ if ((++$cnt) >= $limit) {
+ break;
+ }
+ }
+ $rs->close();
+ return $cnt;
+ }
+
/**
* Returns parent file_info instance
*
return $children;
}
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ global $DB;
+ $cnt = 0;
+ if (($child = $this->get_area_coursecat_description(0, '/', '.'))
+ && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+ return $cnt;
+ }
+
+ $rs = $DB->get_recordset_sql('SELECT ctx.id contextid, c.visible
+ FROM {context} ctx, {course} c
+ WHERE ctx.instanceid = c.id
+ AND ctx.contextlevel = :courselevel
+ AND c.category = :categoryid
+ ORDER BY c.visible DESC', // retrieve visible courses first
+ array('categoryid' => $this->category->id, 'courselevel' => CONTEXT_COURSE));
+ foreach ($rs as $record) {
+ $context = context::instance_by_id($record->contextid);
+ if (!$record->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
+ continue;
+ }
+ if (($child = $this->browser->get_file_info($context))
+ && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+ break;
+ }
+ }
+ $rs->close();
+ if ($cnt >= $limit) {
+ return $cnt;
+ }
+
+ $rs = $DB->get_recordset_sql('SELECT ctx.id contextid, cat.visible
+ FROM {context} ctx, {course_categories} cat
+ WHERE ctx.instanceid = cat.id
+ AND ctx.contextlevel = :catlevel
+ AND cat.parent = :categoryid
+ ORDER BY cat.visible DESC', // retrieve visible categories first
+ array('categoryid' => $this->category->id, 'catlevel' => CONTEXT_COURSECAT));
+ foreach ($rs as $record) {
+ $context = context::instance_by_id($record->contextid);
+ if (!$record->visible and !has_capability('moodle/category:viewhiddencategories', $context)) {
+ continue;
+ }
+ if (($child = $this->browser->get_file_info($context))
+ && $child->count_non_empty_children($extensions) && (++$cnt) >= $limit) {
+ break;
+ }
+ }
+ $rs->close();
+
+ return $cnt;
+ }
+
/**
* Returns parent file_info instance
*
protected $modname;
/** @var array Available file areas */
protected $areas;
+ /** @var array caches the result of last call to get_non_empty_children() */
+ protected $nonemptychildren;
/**
* Constructor
$this->course = $course;
$this->cm = $cm;
$this->modname = $modname;
+ $this->nonemptychildren = null;
include_once("$CFG->dirroot/mod/$modname/lib.php");
* @return array of file_info instances
*/
public function get_children() {
- $children = array();
+ return $this->get_filtered_children('*', false, true);
+ }
- if ($child = $this->get_area_backup(0, '/', '.')) {
- $children[] = $child;
- }
- if ($child = $this->get_area_intro(0, '/', '.')) {
- $children[] = $child;
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+ global $DB;
+ // prepare list of areas including intro and backup
+ $areas = array(
+ array('mod_'.$this->modname, 'intro'),
+ array('backup', 'activity')
+ );
+ foreach ($this->areas as $area => $desctiption) {
+ $areas[] = array('mod_'.$this->modname, $area);
}
- foreach ($this->areas as $area=>$desctiption) {
- if ($child = $this->get_file_info('mod_'.$this->modname, $area, null, null, null)) {
- $children[] = $child;
+ $params1 = array('contextid' => $this->context->id, 'emptyfilename' => '.');
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $children = array();
+ foreach ($areas as $area) {
+ if (!$returnemptyfolders) {
+ // fast pre-check if there are any files in the filearea
+ $params1['component'] = $area[0];
+ $params1['filearea'] = $area[1];
+ if (!$DB->record_exists_sql('SELECT 1 from {files}
+ WHERE contextid = :contextid
+ AND filename <> :emptyfilename
+ AND component = :component
+ AND filearea = :filearea '.$sql2,
+ array_merge($params1, $params2))) {
+ continue;
+ }
+ }
+ if ($child = $this->get_file_info($area[0], $area[1], null, null, null)) {
+ if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+ $children[] = $child;
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
+ }
+ }
}
}
-
+ if ($countonly !== false) {
+ return count($children);
+ }
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ if ($this->nonemptychildren !== null) {
+ return $this->nonemptychildren;
+ }
+ $this->nonemptychildren = $this->get_filtered_children($extensions);
+ return $this->nonemptychildren;
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ if ($this->nonemptychildren !== null) {
+ return count($this->nonemptychildren);
+ }
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
*
return $result;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ $result = array();
+ if (!$this->lf->is_directory()) {
+ return $result;
+ }
+
+ $fs = get_file_storage();
+
+ $storedfiles = $fs->get_directory_files($this->context->id, $this->lf->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(),
+ $this->lf->get_filepath(), false, true, "filepath, filename");
+ foreach ($storedfiles as $file) {
+ $extension = textlib::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
+ if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
+ $fileinfo = new file_info_stored($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
+ $this->itemidused, $this->readaccess, $this->writeaccess, false);
+ if (!$file->is_directory() || $fileinfo->count_non_empty_children($extensions)) {
+ $result[] = $fileinfo;
+ }
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ global $DB;
+ if (!$this->lf->is_directory()) {
+ return 0;
+ }
+
+ $filepath = $this->lf->get_filepath();
+ $length = textlib::strlen($filepath);
+ $sql = "SELECT filepath, filename
+ FROM {files} f
+ WHERE f.contextid = :contextid AND f.component = :component AND f.filearea = :filearea AND f.itemid = :itemid
+ AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
+ AND filename <> '.' ";
+ $params = array('contextid' => $this->context->id,
+ 'component' => $this->lf->get_component(),
+ 'filearea' => $this->lf->get_filearea(),
+ 'itemid' => $this->lf->get_itemid(),
+ 'filepath' => $filepath);
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $rs = $DB->get_recordset_sql($sql.' '.$sql2, array_merge($params, $params2));
+ $children = array();
+ foreach ($rs as $record) {
+ // we don't need to check access to individual files here, since the user can access parent
+ if ($record->filepath === $filepath) {
+ $children[] = $record->filename;
+ } else {
+ $path = explode('/', textlib::substr($record->filepath, $length));
+ if (!in_array($path[0], $children)) {
+ $children[] = $path[0];
+ }
+ }
+ if (count($children) >= $limit) {
+ break;
+ }
+ }
+ $rs->close();
+ return count($children);
+ }
+
/**
* Returns parent file_info instance
*
'dir' => array ('type'=>'application/x-director', 'icon'=>'flash'),
'dxr' => array ('type'=>'application/x-director', 'icon'=>'flash'),
'eps' => array ('type'=>'application/postscript', 'icon'=>'eps'),
+ 'epub' => array ('type'=>'application/epub+zip', 'icon'=>'epub', 'groups'=>array('document')),
'fdf' => array ('type'=>'application/pdf', 'icon'=>'pdf'),
'flv' => array ('type'=>'video/x-flv', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
'f4v' => array ('type'=>'video/mp4', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
$a[strtoupper($key)] = strtoupper($value);
$a[ucfirst($key)] = ucfirst($value);
}
- if (get_string_manager()->string_exists($mimetype, 'mimetypes')) {
- $result = get_string($mimetype, 'mimetypes', (object)$a);
- } else if (get_string_manager()->string_exists($mimetypestr, 'mimetypes')) {
- $result = get_string($mimetypestr, 'mimetypes', (object)$a);
+
+ // MIME types may include + symbol but this is not permitted in string ids.
+ $safemimetype = str_replace('+', '_', $mimetype);
+ $safemimetypestr = str_replace('+', '_', $mimetypestr);
+ if (get_string_manager()->string_exists($safemimetype, 'mimetypes')) {
+ $result = get_string($safemimetype, 'mimetypes', (object)$a);
+ } else if (get_string_manager()->string_exists($safemimetypestr, 'mimetypes')) {
+ $result = get_string($safemimetypestr, 'mimetypes', (object)$a);
} else if (get_string_manager()->string_exists('default', 'mimetypes')) {
$result = get_string('default', 'mimetypes', (object)$a);
} else {
config.september,
config.october,
config.november,
- config.december ],
+ config.december ]
});
this.calendar.changePageEvent.subscribe(function(){
this.fix_position();
$function = 'M.form.dateselector.init_date_selectors';
$config = array(array(
'firstdayofweek' => get_string('firstdayofweek', 'langconfig'),
- 'mon' => strftime('%a', strtotime("Monday")),
- 'tue' => strftime('%a', strtotime("Tuesday")),
- 'wed' => strftime('%a', strtotime("Wednesday")),
- 'thu' => strftime('%a', strtotime("Thursday")),
- 'fri' => strftime('%a', strtotime("Friday")),
- 'sat' => strftime('%a', strtotime("Saturday")),
- 'sun' => strftime('%a', strtotime("Sunday")),
- 'january' => strftime('%B', strtotime("January 1")),
- 'february' => strftime('%B', strtotime("February 1")),
- 'march' => strftime('%B', strtotime("March 1")),
- 'april' => strftime('%B', strtotime("April 1")),
- 'may' => strftime('%B', strtotime("May 1")),
- 'june' => strftime('%B', strtotime("June 1")),
- 'july' => strftime('%B', strtotime("July 1")),
- 'august' => strftime('%B', strtotime("August 1")),
- 'september' => strftime('%B', strtotime("September 1")),
- 'october' => strftime('%B', strtotime("October 1")),
- 'november' => strftime('%B', strtotime("November 1")),
- 'december' => strftime('%B', strtotime("December 1"))
+ 'mon' => date_format_string(strtotime("Monday"), '%a', 99),
+ 'tue' => date_format_string(strtotime("Tuesday"), '%a', 99),
+ 'wed' => date_format_string(strtotime("Wednesday"), '%a', 99),
+ 'thu' => date_format_string(strtotime("Thursday"), '%a', 99),
+ 'fri' => date_format_string(strtotime("Friday"), '%a', 99),
+ 'sat' => date_format_string(strtotime("Saturday"), '%a', 99),
+ 'sun' => date_format_string(strtotime("Sunday"), '%a', 99),
+ 'january' => date_format_string(strtotime("January 1"), '%B', 99),
+ 'february' => date_format_string(strtotime("February 1"), '%B', 99),
+ 'march' => date_format_string(strtotime("March 1"), '%B', 99),
+ 'april' => date_format_string(strtotime("April 1"), '%B', 99),
+ 'may' => date_format_string(strtotime("May 1"), '%B', 99),
+ 'june' => date_format_string(strtotime("June 1"), '%B', 99),
+ 'july' => date_format_string(strtotime("July 1"), '%B', 99),
+ 'august' => date_format_string(strtotime("August 1"), '%B', 99),
+ 'september' => date_format_string(strtotime("September 1"), '%B', 99),
+ 'october' => date_format_string(strtotime("October 1"), '%B', 99),
+ 'november' => date_format_string(strtotime("November 1"), '%B', 99),
+ 'december' => date_format_string(strtotime("December 1"), '%B', 99)
));
$PAGE->requires->yui_module($module, $function, $config);
$done = true;
/** @var bool Whether to display advanced elements (on page load) */
var $_showAdvanced = null;
+ /** @var bool whether to automatically initialise M.formchangechecker for this form. */
+ protected $_use_form_change_checker = true;
+
/**
* The form name is derived from the class name of the wrapper minus the trailing form
* It is a name with words joined by underscores whereas the id attribute is words joined by underscores.
return $this->_showAdvanced;
}
+ /**
+ * Call this method if you don't want the formchangechecker JavaScript to be
+ * automatically initialised for this form.
+ */
+ public function disable_form_change_checker() {
+ $this->_use_form_change_checker = false;
+ }
- /**
+ /**
+ * If you have called {@link disable_form_change_checker()} then you can use
+ * this method to re-enable it. It is enabled by default, so normally you don't
+ * need to call this.
+ */
+ public function enable_form_change_checker() {
+ $this->_use_form_change_checker = true;
+ }
+
+ /**
+ * @return bool whether this form should automatically initialise
+ * formchangechecker for itself.
+ */
+ public function is_form_change_checker_enabled() {
+ return $this->_use_form_change_checker;
+ }
+
+ /**
* Accepts a renderer
*
* @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
$this->_hiddenHtml .= $form->_pageparams;
}
- $PAGE->requires->yui_module('moodle-core-formchangechecker',
- 'M.core_formchangechecker.init',
- array(array(
- 'formid' => $form->getAttribute('id')
- ))
- );
- $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+ if ($form->is_form_change_checker_enabled()) {
+ $PAGE->requires->yui_module('moodle-core-formchangechecker',
+ 'M.core_formchangechecker.init',
+ array(array(
+ 'formid' => $form->getAttribute('id')
+ ))
+ );
+ $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+ }
}
/**
$i = 1;
while ($originalindex+$i < count($grade_keys)) {
+
$possibleitemid = $grade_keys[$originalindex+$i];
+ $i++;
+
if ($grade_values[$founditemid] != $grade_values[$possibleitemid]) {
// The next grade item has a different grade. Stop looking.
break;
$founditemid = $possibleitemid;
// Continue searching to see if there is an even higher grademax...
}
-
- $i++;
}
// Now drop whatever grade item we have found
$this->assertEquals(count($grades), 1);
$this->assertEquals($grades[$this->grade_items[2]->id], 6);
+ // MDL-35667 - There was an infinite loop if several items had the same grade and at least one was extra credit
+ $category = new grade_category();
+ $category->droplow = 1;
+ $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+ $items[$this->grade_items[1]->id]->aggregationcoef = 1; // Mark grade item 1 as "extra credit"
+ $grades = array($this->grade_items[0]->id=>1, // 1 out of 110. Should be excluded from aggregation.
+ $this->grade_items[1]->id=>1, // 1 out of 100. Extra credit. Should be retained.
+ $this->grade_items[2]->id=>1, // 1 out of 6. Should be retained.
+ $this->grade_items[4]->id=>1);// 1 out of 100. Should be retained.
+ $category->apply_limit_rules($grades, $items);
+ $this->assertEquals(count($grades), 3);
+ $this->assertEquals($grades[$this->grade_items[1]->id], 1);
+ $this->assertEquals($grades[$this->grade_items[2]->id], 1);
+ $this->assertEquals($grades[$this->grade_items[4]->id], 1);
+
}
/**
}
}
+M.util.help_popups = {
+ setup : function(Y) {
+ Y.one('body').delegate('click', this.open_popup, 'a.helplinkpopup', this);
+ },
+ open_popup : function(e) {
+ // Prevent the default page action
+ e.preventDefault();
+
+ // Grab the anchor that was clicked
+ var anchor = e.target.ancestor('a', true);
+ var args = {
+ 'name' : 'popup',
+ 'url' : anchor.getAttribute('href'),
+ 'options' : ''
+ };
+ var options = [
+ 'height=600',
+ 'width=800',
+ 'top=0',
+ 'left=0',
+ 'menubar=0',
+ 'location=0',
+ 'scrollbars',
+ 'resizable',
+ 'toolbar',
+ 'status',
+ 'directories=0',
+ 'fullscreen=0',
+ 'dependent'
+ ]
+ args.options = options.join(',');
+
+ openpopup(e, args);
+ }
+}
+
M.util.help_icon = {
Y : null,
instance : null,
event.preventDefault();
if (M.util.help_icon.instance === null) {
var Y = M.util.help_icon.Y;
- Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', function(Y) {
+ Y.use('overlay', 'io-base', 'event-mouseenter', 'node', 'event-key', 'escape', function(Y) {
var help_content_overlay = {
helplink : null,
overlay : null,
init : function() {
- var closebtn = Y.Node.create('<a id="closehelpbox" href="#"><img src="'+M.util.image_url('t/delete', 'moodle')+'" /></a>');
+ var strclose = Y.Escape.html(M.str.form.close);
+ var footerbtn = Y.Node.create('<button class="closebtn">'+strclose+'</button>');
// Create an overlay from markup
this.overlay = new Y.Overlay({
- headerContent: closebtn,
+ footerContent: footerbtn,
bodyContent: '',
id: 'helppopupbox',
width:'400px',
});
this.overlay.render(Y.one(document.body));
- closebtn.on('click', this.overlay.hide, this.overlay);
+ footerbtn.on('click', this.overlay.hide, this.overlay);
var boundingBox = this.overlay.get("boundingBox");
this.overlay.hide();
}
}, this);
-
- Y.on("key", this.close, closebtn , "down:13", this);
- closebtn.on('click', this.close, this);
},
close : function(e) {
},
display : function(event, args) {
+ if (Y.one('html').get('dir') == 'rtl') {
+ var overlayPosition = [Y.WidgetPositionAlign.TR, Y.WidgetPositionAlign.LC];
+ } else {
+ var overlayPosition = [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.RC];
+ }
+
this.helplink = args.node;
+
this.overlay.set('bodyContent', Y.Node.create('<img src="'+M.cfg.loadingicon+'" class="spinner" />'));
- this.overlay.set("align", {node:args.node, points:[Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.RC]});
+ this.overlay.set("align", {node:args.node, points: overlayPosition});
var fullurl = args.url;
if (!args.url.match(/https?:\/\//)) {
Y.io(ajaxurl, cfg);
this.overlay.show();
-
- Y.one('#closehelpbox').focus();
},
display_callback : function(content) {
// (because it's impossible to specify UTF-8 to fetch locale info in Win32)
if (abs($timezone) > 13) { /// Server time
- if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
- $format = textlib::convert($format, 'utf-8', $localewincharset);
- $datestring = strftime($format, $date);
- $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
- } else {
- $datestring = strftime($format, $date);
- }
+ $datestring = date_format_string($date, $format, $timezone);
if ($fixday) {
$daystring = ltrim(str_replace(array(' 0', ' '), '', strftime(' %d', $date)));
$datestring = str_replace('DD', $daystring, $datestring);
} else {
$date += (int)($timezone * 3600);
- if ($CFG->ostype == 'WINDOWS' and ($localewincharset = get_string('localewincharset', 'langconfig'))) {
- $format = textlib::convert($format, 'utf-8', $localewincharset);
- $datestring = gmstrftime($format, $date);
- $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
- } else {
- $datestring = gmstrftime($format, $date);
- }
+ $datestring = date_format_string($date, $format, $timezone);
if ($fixday) {
$daystring = ltrim(str_replace(array(' 0', ' '), '', gmstrftime(' %d', $date)));
$datestring = str_replace('DD', $daystring, $datestring);
return $datestring;
}
+/**
+ * Returns a formatted date ensuring it is UTF-8.
+ *
+ * If we are running under Windows convert to Windows encoding and then back to UTF-8
+ * (because it's impossible to specify UTF-8 to fetch locale info in Win32).
+ *
+ * This function does not do any calculation regarding the user preferences and should
+ * therefore receive the final date timestamp, format and timezone. Timezone being only used
+ * to differenciate the use of server time or not (strftime() against gmstrftime()).
+ *
+ * @param int $date the timestamp.
+ * @param string $format strftime format.
+ * @param int|float $timezone the numerical timezone, typically returned by {@link get_user_timezone_offset()}.
+ * @return string the formatted date/time.
+ * @since 2.3.3
+ */
+function date_format_string($date, $format, $tz = 99) {
+ global $CFG;
+ if (abs($tz) > 13) {
+ if ($CFG->ostype == 'WINDOWS') {
+ $localewincharset = get_string('localewincharset', 'langconfig');
+ $format = textlib::convert($format, 'utf-8', $localewincharset);
+ $datestring = strftime($format, $date);
+ $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
+ } else {
+ $datestring = strftime($format, $date);
+ }
+ } else {
+ if ($CFG->ostype == 'WINDOWS') {
+ $localewincharset = get_string('localewincharset', 'langconfig');
+ $format = textlib::convert($format, 'utf-8', $localewincharset);
+ $datestring = gmstrftime($format, $date);
+ $datestring = textlib::convert($datestring, $localewincharset, 'utf-8');
+ } else {
+ $datestring = gmstrftime($format, $date);
+ }
+ }
+ return $datestring;
+}
+
/**
* Given a $time timestamp in GMT (seconds since epoch),
* returns an array that represents the date in user time
case 'Gecko': /// Gecko based browsers
- if (empty($version) and substr_count($agent, 'Camino')) {
- // MacOS X Camino support
- $version = 20041110;
+ // Do not look for dates any more, we expect real Firefox version here.
+ if (empty($version)) {
+ $version = 1;
+ } else if ($version > 20000000) {
+ // This is just a guess, it is not supposed to be 100% accurate!
+ if (preg_match('/^201/', $version)) {
+ $version = 3.6;
+ } else if (preg_match('/^200[7-9]/', $version)) {
+ $version = 3;
+ } else if (preg_match('/^2006/', $version)) {
+ $version = 2;
+ } else {
+ $version = 1.5;
+ }
}
-
- // the proper string - Gecko/CCYYMMDD Vendor/Version
- // Faster version and work-a-round No IDN problem.
- if (preg_match("/Gecko\/([0-9]+)/i", $agent, $match)) {
- if ($match[1] > $version) {
- return true;
+ if (preg_match("/(Iceweasel|Firefox)\/([0-9\.]+)/i", $agent, $match)) {
+ // Use real Firefox version if specified in user agent string.
+ if (version_compare($match[2], $version) >= 0) {
+ return true;
+ }
+ } else if (preg_match("/Gecko\/([0-9\.]+)/i", $agent, $match)) {
+ // Gecko might contain date or Firefox revision, let's just guess the Firefox version from the date.
+ $browserver = $match[1];
+ if ($browserver > 20000000) {
+ // This is just a guess, it is not supposed to be 100% accurate!
+ if (preg_match('/^201/', $browserver)) {
+ $browserver = 3.6;
+ } else if (preg_match('/^200[7-9]/', $browserver)) {
+ $browserver = 3;
+ } else if (preg_match('/^2006/', $version)) {
+ $browserver = 2;
+ } else {
+ $browserver = 1.5;
}
}
+ if (version_compare($browserver, $version) >= 0) {
+ return true;
+ }
+ }
break;
break;
case CONTEXT_COURSECAT :
// This has already been loaded we just need to map the variable
- if ($showcategories) {
+ if ($this->show_categories()) {
$this->load_all_categories($this->page->context->instanceid, true);
}
break;
$baseurl->param('sesskey', sesskey());
} else {
// Edit on the main course page.
- $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'sesskey'=>sesskey()));
+ $baseurl = new moodle_url('/course/view.php', array('id'=>$course->id, 'return'=>$this->page->url->out_as_local_url(false), 'sesskey'=>sesskey()));
}
$editurl = clone($baseurl);
// flow player embedding support
$this->page->requires->js_function_call('M.util.load_flowplayer');
+ // Set up help link popups for all links with the helplinkpopup class
+ $this->page->requires->js_init_call('M.util.help_popups.setup');
+
$this->page->requires->js_function_call('setTimeout', array('fix_column_widths()', 20));
$focus = $this->page->focuscontrol;
*
* @param string $path The page link after doc root and language, no leading slash.
* @param string $text The text to be displayed for the link
+ * @param boolean $forcepopup Whether to force a popup regardless of the value of $CFG->doctonewwindow
* @return string
*/
- public function doc_link($path, $text = '') {
+ public function doc_link($path, $text = '', $forcepopup = false) {
global $CFG;
$icon = $this->pix_icon('docs', $text, 'moodle', array('class'=>'iconhelp'));
$url = new moodle_url(get_docs_url($path));
$attributes = array('href'=>$url);
- if (!empty($CFG->doctonewwindow)) {
- $attributes['id'] = $this->add_action_handler(new popup_action('click', $url));
+ if (!empty($CFG->doctonewwindow) || $forcepopup) {
+ $attributes['class'] = 'helplinkpopup';
}
return html_writer::tag('a', $icon.$text, $attributes);
$output = html_writer::tag('a', $output, $attributes);
$this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+ $this->page->requires->string_for_js('close', 'form');
// and finally span
return html_writer::tag('span', $output, array('class' => 'helplink'));
$output = html_writer::tag('a', $output, $attributes);
$this->page->requires->js_init_call('M.util.help_icon.add', array(array('id'=>$id, 'url'=>$url->out(false))));
+ $this->page->requires->string_for_js('close', 'form');
// and finally span
return html_writer::tag('span', $output, array('class' => 'helplink'));
}
if (!isset($record['username'])) {
- $record['username'] = textlib::strtolower($record['firstname']).textlib::strtolower($record['lastname']);
+ $record['username'] = 'username'.$i;
+ $j = 2;
while ($DB->record_exists('user', array('username'=>$record['username'], 'mnethostid'=>$record['mnethostid']))) {
- $record['username'] = $record['username'].'_'.$i;
+ $record['username'] = 'username'.$i.'_'.$j;
+ $j++;
}
}
public static function reset_all_data($logchanges = false) {
global $DB, $CFG, $USER, $SITE, $COURSE, $PAGE, $OUTPUT, $SESSION, $GROUPLIB_CACHE;
+ // Release memory and indirectly call destroy() methods to release resource handles, etc.
+ gc_collect_cycles();
+
// reset global $DB in case somebody mocked it
$DB = self::get_global_backup('DB');
$GROUPLIB_CACHE = null;
//TODO MDL-25290: add more resets here and probably refactor them to new core function
+ // Reset course and module caches.
+ $reset = 'reset';
+ get_fast_modinfo($reset);
+
// purge dataroot directory
self::reset_dataroot();
$count = $DB->count_records('user');
$user = $generator->create_user();
$this->assertEquals($count+1, $DB->count_records('user'));
+ $this->assertSame($user->username, clean_param($user->username, PARAM_USERNAME));
+ $this->assertSame($user->email, clean_param($user->email, PARAM_EMAIL));
+ $user = $generator->create_user(array('firstname'=>'Žluťoučký', 'lastname'=>'Koníček'));
+ $this->assertSame($user->username, clean_param($user->username, PARAM_USERNAME));
+ $this->assertSame($user->email, clean_param($user->email, PARAM_EMAIL));
$count = $DB->count_records('course_categories');
$category = $generator->create_category();
public function get_uninstall_url() {
return new moodle_url('/admin/localplugins.php', array('delete' => $this->name, 'sesskey' => sesskey()));
}
-
- public function get_settings_url() {
- if (file_exists($this->full_path('settings.php'))) {
- return new moodle_url('/admin/settings.php', array('section' => 'local_' . $this->name));
- } else {
- return parent::get_settings_url();
- }
- }
}
function col_fullname($row) {
global $COURSE, $CFG;
- if (!$this->download) {
- $profileurl = new moodle_url('/user/profile.php', array('id' => $row->{$this->useridfield}));
- if ($COURSE->id != SITEID) {
- $profileurl->param('course', $COURSE->id);
- }
- return html_writer::link($profileurl, fullname($row));
+ $name = fullname($row);
+ if ($this->download) {
+ return $name;
+ }
+ $userid = $row->{$this->useridfield};
+ if ($COURSE->id == SITEID) {
+ $profileurl = new moodle_url('/user/profile.php', array('id' => $userid));
} else {
- return fullname($row);
+ $profileurl = new moodle_url('/user/view.php',
+ array('id' => $userid, 'course' => $COURSE->id));
}
+ return html_writer::link($profileurl, $name);
}
/**
'1.5' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; nl; rv:1.8) Gecko/20051107 Firefox/1.5'),
'1.5.0.1' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1'),
'2.0' => array('Windows XP' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1',
- 'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)'),
- '3.0.6' => array('SUSE' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6'),
+ 'Ubuntu Linux AMD64' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8.1) Gecko/20060601 Firefox/2.0 (Ubuntu-edgy)'),
+ '3.0.6' => array('SUSE' => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.6) Gecko/2009012700 SUSE/3.0.6-1.4 Firefox/3.0.6'),
+ '3.6' => array('Linux' => 'Mozilla/5.0 (X11; Linux i686; rv:2.0) Gecko/20100101 Firefox/3.6'),
+ '11.0' => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0) Gecko Firefox/11.0'),
+ '15.0a2' => array('Windows' => 'Mozilla/5.0 (Windows NT 6.1; rv:15.0) Gecko/20120716 Firefox/15.0a2'),
+ '18.0' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:18.0) Gecko/18.0 Firefox/18.0'),
+ ),
+ 'SeaMonkey' => array(
+ '2.0' => array('Windows' => 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1b3pre) Gecko/20081208 SeaMonkey/2.0'),
+ '2.1' => array('Linux' => 'Mozilla/5.0 (X11; Linux x86_64; rv:2.0.1) Gecko/20110609 Firefox/4.0.1 SeaMonkey/2.1'),
+ '2.3' => array('FreeBSD' => 'Mozilla/5.0 (X11; FreeBSD amd64; rv:6.0) Gecko/20110818 Firefox/6.0 SeaMonkey/2.3'),
),
'Safari' => array(
'312' => array('Mac OS X' => 'Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en-us) AppleWebKit/312.1 (KHTML, like Gecko) Safari/312'),
$this->assertTrue(check_browser_version('Firefox'));
$this->assertTrue(check_browser_version('Firefox', '1.5'));
$this->assertFalse(check_browser_version('Firefox', '3.0'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['1.0.6']['Windows XP'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Gecko', '1'));
+ $this->assertFalse(check_browser_version('Gecko', 20030516));
+ $this->assertFalse(check_browser_version('Gecko', 20051106));
+ $this->assertFalse(check_browser_version('Gecko', 2006010100));
+ $this->assertFalse(check_browser_version('Firefox', '1.5'));
+ $this->assertFalse(check_browser_version('Firefox', '3.0'));
+ $this->assertFalse(check_browser_version('Gecko', '2'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['2.0']['Windows XP'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', '1.5'));
+ $this->assertTrue(check_browser_version('Gecko', '1'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertFalse(check_browser_version('Firefox', '3.0'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', '1.5'));
+ $this->assertTrue(check_browser_version('Firefox', '3.0'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', '3.6'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertFalse(check_browser_version('Firefox', '4'));
+ $this->assertFalse(check_browser_version('Firefox', '10'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['3.6']['Linux'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', '1.5'));
+ $this->assertTrue(check_browser_version('Firefox', '3.0'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', '3.6'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertFalse(check_browser_version('Firefox', '4'));
+ $this->assertFalse(check_browser_version('Firefox', '10'));
+ $this->assertFalse(check_browser_version('Firefox', '18'));
+ $this->assertFalse(check_browser_version('Gecko', '4'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['15.0a2']['Windows'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', '1.5'));
+ $this->assertTrue(check_browser_version('Firefox', '3.0'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', '3.6'));
+ $this->assertTrue(check_browser_version('Gecko', '15.0'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertTrue(check_browser_version('Firefox', '4'));
+ $this->assertTrue(check_browser_version('Firefox', '10'));
+ $this->assertTrue(check_browser_version('Firefox', '15'));
+ $this->assertFalse(check_browser_version('Firefox', '18'));
+ $this->assertFalse(check_browser_version('Gecko', '18'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['Firefox']['18.0']['Mac OS X'];
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', '1.5'));
+ $this->assertTrue(check_browser_version('Firefox', '3.0'));
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', '3.6'));
+ $this->assertTrue(check_browser_version('Gecko', '15.0'));
+ $this->assertTrue(check_browser_version('Gecko', '18.0'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertTrue(check_browser_version('Firefox', '4'));
+ $this->assertTrue(check_browser_version('Firefox', '10'));
+ $this->assertTrue(check_browser_version('Firefox', '15'));
+ $this->assertTrue(check_browser_version('Firefox', '18'));
+ $this->assertFalse(check_browser_version('Firefox', '19'));
+ $this->assertFalse(check_browser_version('Gecko', '19'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.0']['Windows'];
+
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertFalse(check_browser_version('Gecko', '3.6'));
+ $this->assertFalse(check_browser_version('Gecko', '4.0'));
+ $this->assertFalse(check_browser_version('Firefox'));
+
+ $_SERVER['HTTP_USER_AGENT'] = $this->user_agents['SeaMonkey']['2.1']['Linux'];
+ $this->assertTrue(check_browser_version('Gecko', '2'));
+ $this->assertTrue(check_browser_version('Gecko', '3.6'));
+ $this->assertTrue(check_browser_version('Gecko', '4.0'));
+ $this->assertTrue(check_browser_version('Gecko', 20030516));
+ $this->assertTrue(check_browser_version('Gecko', 20051106));
+ $this->assertTrue(check_browser_version('Gecko', 2006010100));
+ $this->assertTrue(check_browser_version('Firefox'));
+ $this->assertTrue(check_browser_version('Firefox', 4.0));
+ $this->assertFalse(check_browser_version('Firefox', 5));
+ $this->assertFalse(check_browser_version('Gecko', '18.0'));
+
}
function test_get_browser_version_classes() {
);
$this->assertEquals(convert_to_array($obj), $ar);
}
+
+ /**
+ * Test the function date_format_string().
+ */
+ function test_date_format_string() {
+ // Forcing locale and timezone.
+ $oldlocale = setlocale(LC_TIME, '0');
+ setlocale(LC_TIME, 'en_AU.UTF-8');
+ $systemdefaulttimezone = date_default_timezone_get();
+ date_default_timezone_set('Australia/Perth');
+
+ $tests = array(
+ array(
+ 'tz' => 99,
+ 'str' => '%A, %d %B %Y, %I:%M %p',
+ 'expected' => 'Saturday, 01 January 2011, 06:00 PM'
+ ),
+ array(
+ 'tz' => 0,
+ 'str' => '%A, %d %B %Y, %I:%M %p',
+ 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
+ ),
+ array(
+ 'tz' => -12,
+ 'str' => '%A, %d %B %Y, %I:%M %p',
+ 'expected' => 'Saturday, 01 January 2011, 10:00 AM'
+ ),
+ array(
+ 'tz' => 99,
+ 'str' => 'Žluťoučký koníček %A',
+ 'expected' => 'Žluťoučký koníček Saturday'
+ ),
+ array(
+ 'tz' => 99,
+ 'str' => '言語設定言語 %A',
+ 'expected' => '言語設定言語 Saturday'
+ ),
+ array(
+ 'tz' => 99,
+ 'str' => '简体中文简体 %A',
+ 'expected' => '简体中文简体 Saturday'
+ ),
+ );
+
+ // Note: date_format_string() uses the timezone only to differenciate
+ // the server time from the UTC time. It does not modify the timestamp.
+ // Hence similar results for timezones <= 13.
+ // On different systems case of AM PM changes so compare case insensitive.
+ foreach ($tests as $test) {
+ $str = date_format_string(1293876000, $test['str'], $test['tz']);
+ $this->assertEquals(textlib::strtolower($test['expected']), textlib::strtolower($str));
+ }
+
+ // Restore system default values.
+ date_default_timezone_set($systemdefaulttimezone);
+ setlocale(LC_TIME, $oldlocale);
+ }
}
$dbfunction->classpath = $function['classpath'];
$update = true;
}
- $functioncapabilities = key_exists('capabilities', $function)?$function['capabilities']:'';
+ $functioncapabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
if ($dbfunction->capabilities != $functioncapabilities) {
$dbfunction->capabilities = $functioncapabilities;
$update = true;
$dbfunction->methodname = $function['methodname'];
$dbfunction->classpath = empty($function['classpath']) ? null : $function['classpath'];
$dbfunction->component = $component;
- $dbfunction->capabilities = key_exists('capabilities', $function)?$function['capabilities']:'';
+ $dbfunction->capabilities = array_key_exists('capabilities', $function)?$function['capabilities']:'';
$dbfunction->id = $DB->insert_record('external_functions', $dbfunction);
}
unset($functions);
// collapsible course summary
if (!empty($course->summary)) {
- unset($options);
+ $options = new stdClass();
$options->trusted = false;
$options->para = false;
$options->filter = false;
}
}
+ /**
+ * This is required so when using "Save and next", each form is not defaulted to the previous form.
+ * Giving each form a unique identitifer is enough to prevent this (include the rownum in the form name).
+ *
+ * @return string - The unique identifier for this form.
+ */
+ protected function get_form_identifier() {
+ $params = $this->_customdata[2];
+ return get_class($this) . '_' . $params['rownum'];
+ }
+
/**
* Perform minimal validation on the grade form
* @param array $data
function definition() {
$mform = $this->_form;
$instance = $this->_customdata;
+ $dirtyclass = array('class'=>'ignoredirty');
$mform->addElement('header', 'general', get_string('gradingoptions', 'assign'));
// visible elements
$options = array(-1=>get_string('all'),10=>'10', 20=>'20', 50=>'50', 100=>'100');
- $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
+ $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options, $dirtyclass);
$options = array('' => get_string('filternone', 'assign'),
ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'),
ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign'));
if ($instance['submissionsenabled']) {
- $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+ $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options, $dirtyclass);
}
// quickgrading
$string['currentgrade'] = 'Current grade in gradebook';
$string['defaultplugins'] = 'Default assignment settings';
$string['defaultplugins_help'] = 'These settings define the defaults for all new assignments.';
+$string['deleteallsubmissions'] = 'Delete all submissions';
$string['deletepluginareyousure'] = 'Delete assignment plugin {$a}: are you sure?';
$string['deletepluginareyousuremessage'] = 'You are about to completely delete the assignment plugin {$a}. This will completely delete everything in the database associated with this assignment plugin. Are you SURE you want to continue?';
$string['deletingplugin'] = 'Deleting plugin {$a}.';
return $assignment->delete_instance();
}
+/**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * This function will remove all assignment submissions and feedbacks in the database
+ * and clean up any related data.
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function assign_reset_userdata($data) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+ $status = array();
+ $params = array('courseid'=>$data->courseid);
+ $sql = "SELECT a.id FROM {assign} a WHERE a.course=:courseid";
+ $course = $DB->get_record('course', array('id'=> $data->courseid), '*', MUST_EXIST);
+ if ($assigns = $DB->get_records_sql($sql,$params)) {
+ foreach ($assigns as $assign) {
+ $cm = get_coursemodule_from_instance('assign', $assign->id, $data->courseid, false, MUST_EXIST);
+ $context = context_module::instance($cm->id);
+ $assignment = new assign($context, $cm, $course);
+ $status = array_merge($status, $assignment->reset_userdata($data));
+ }
+ }
+ return $status;
+}
+
+/**
+ * Removes all grades from gradebook
+ *
+ * @param int $courseid The ID of the course to reset
+ * @param string $type Optional type of assignment to limit the reset to a particular assignment type
+ */
+function assign_reset_gradebook($courseid, $type='') {
+ global $CFG, $DB;
+
+ $params = array('moduletype'=>'assign','courseid'=>$courseid);
+ $sql = 'SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
+ FROM {assign} a, {course_modules} cm, {modules} m
+ WHERE m.name=:moduletype AND m.id=cm.module AND cm.instance=a.id AND a.course=:courseid';
+
+ if ($assignments = $DB->get_records_sql($sql,$params)) {
+ foreach ($assignments as $assignment) {
+ assign_grade_item_update($assignment, 'reset');
+ }
+ }
+}
+
+/**
+ * Implementation of the function for printing the form elements that control
+ * whether the course reset functionality affects the assignment.
+ * @param $mform form passed by reference
+ */
+function assign_reset_course_form_definition(&$mform) {
+ $mform->addElement('header', 'assignheader', get_string('modulenameplural', 'assign'));
+ $mform->addElement('advcheckbox', 'reset_assign_submissions', get_string('deleteallsubmissions','assign'));
+}
+
+/**
+ * Course reset form defaults.
+ * @param object $course
+ * @return array
+ */
+function assign_reset_course_form_defaults($course) {
+ return array('reset_assign_submissions'=>1);
+}
+
/**
* Update an assignment instance
*
return $result;
}
+ /**
+ * Actual implementation of the reset course functionality, delete all the
+ * assignment submissions for course $data->courseid.
+ *
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+ public function reset_userdata($data) {
+ global $CFG,$DB;
+
+ $componentstr = get_string('modulenameplural', 'assign');
+ $status = array();
+
+ $fs = get_file_storage();
+ if (!empty($data->reset_assign_submissions)) {
+ // Delete files associated with this assignment.
+ foreach ($this->submissionplugins as $plugin) {
+ $fileareas = array();
+ $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+ $fileareas = $plugin->get_file_areas();
+ foreach ($fileareas as $filearea) {
+ $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+ }
+
+ if (!$plugin->delete_instance()) {
+ $status[] = array('component'=>$componentstr,
+ 'item'=>get_string('deleteallsubmissions','assign'),
+ 'error'=>$plugin->get_error());
+ }
+ }
+
+ foreach ($this->feedbackplugins as $plugin) {
+ $fileareas = array();
+ $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+ $fileareas = $plugin->get_file_areas();
+ foreach ($fileareas as $filearea) {
+ $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+ }
+
+ if (!$plugin->delete_instance()) {
+ $status[] = array('component'=>$componentstr,
+ 'item'=>get_string('deleteallsubmissions','assign'),
+ 'error'=>$plugin->get_error());
+ }
+ }
+
+ $assignssql = "SELECT a.id
+ FROM {assign} a
+ WHERE a.course=:course";
+ $params = array ("course" => $data->courseid);
+
+ $DB->delete_records_select('assign_submission', "assignment IN ($assignssql)", $params);
+ $status[] = array('component'=>$componentstr,
+ 'item'=>get_string('deleteallsubmissions','assign'),
+ 'error'=>false);
+
+ if (empty($data->reset_gradebook_grades)) {
+ // Remove all grades from gradebook.
+ require_once($CFG->dirroot.'/mod/assign/lib.php');
+ assign_reset_gradebook($data->courseid);
+ }
+ }
+ // Updating dates - shift may be negative too.
+ if ($data->timeshift) {
+ shift_course_mod_dates('assign',
+ array('duedate', 'allowsubmissionsfromdate'),
+ $data->timeshift,
+ $data->courseid);
+ $status[] = array('component'=>$componentstr,
+ 'item'=>get_string('datechanged'),
+ 'error'=>false);
+ }
+
+ return $status;
+ }
+
/**
* Update the settings for a single plugin
*
}
$completiondone = true;
+ // Migrate log entries so we don't lose them.
+ $logparams = array('cmid' => $oldcoursemodule->id, 'course' => $oldcoursemodule->course);
+ $DB->set_field('log', 'module', 'assign', $logparams);
+ $DB->set_field('log', 'cmid', $newcoursemodule->id, $logparams);
+
// copy all the submission data (and get plugins to do their bit)
$oldsubmissions = $DB->get_records('assignment_submissions', array('assignment'=>$oldassignmentid));
$DB->update_record('course_completion_criteria', $criteria);
}
}
+ // Roll back the log changes
+ $logparams = array('cmid' => $newcoursemodule->id, 'course' => $newcoursemodule->course);
+ $DB->set_field('log', 'module', 'assignment', $logparams);
+ $DB->set_field('log', 'cmid', $oldcoursemodule->id, $logparams);
// roll back the advanced grading update
if ($gradingarea) {
foreach ($gradeidmap as $newgradeid => $oldsubmissionid) {
}
$filename = str_replace(' ', '_', clean_filename($this->course->shortname.'-'.$this->assignment->name.'-'.$groupname.$this->assignment->id.".zip")); //name of new zip file.
foreach ($submissions as $submission) {
- // If assignment is open and submission is not finalized then don't add it to zip.
+ // If assignment is open and submission is not finalized and marking button enabled then don't add it to zip.
$submissionstatus = $this->is_finalized($submission);
- if ($this->isopen() && empty($submissionstatus)) {
+ if ($this->isopen() && empty($submissionstatus) && !empty($this->assignment->var4)) {
continue;
}
$a_userid = $submission->userid; //get userid
// Moodle v2.3.0 release upgrade line
// Put any upgrade step following this
+ // Note: The next steps (up to 2012061710 included, are a "replay" of old upgrade steps,
+ // because some sites updated to Moodle 2.3 didn't have the latest contrib mod_book
+ // installed, so some required changes were missing.
+ //
+ // All the steps are run conditionally so sites upgraded from latest contrib mod_book or
+ // new (2.3 and upwards) sites won't get affected.
+ //
+ // See MDL-35297 and commit msg for more information.
+
+ if ($oldversion < 2012061703) {
+ // Rename field summary on table book to intro
+ $table = new xmldb_table('book');
+ $field = new xmldb_field('summary', XMLDB_TYPE_TEXT, null, null, null, null, null, 'name');
+
+ // Launch rename field summary
+ if ($dbman->field_exists($table, $field)) {
+ $dbman->rename_field($table, $field, 'intro');
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061703, 'book');
+ }
+
+ if ($oldversion < 2012061704) {
+ // Define field introformat to be added to book
+ $table = new xmldb_table('book');
+ $field = new xmldb_field('introformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'intro');
+
+ // Launch add field introformat
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ // Conditionally migrate to html format in intro
+ // Si está activo el htmleditor!!!!!
+ if ($CFG->texteditors !== 'textarea') {
+ $rs = $DB->get_recordset('book', array('introformat'=>FORMAT_MOODLE), '', 'id,intro,introformat');
+ foreach ($rs as $b) {
+ $b->intro = text_to_html($b->intro, false, false, true);
+ $b->introformat = FORMAT_HTML;
+ $DB->update_record('book', $b);
+ upgrade_set_timeout();
+ }
+ unset($b);
+ $rs->close();
+ }
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061704, 'book');
+ }
+
+ if ($oldversion < 2012061705) {
+ // Define field introformat to be added to book
+ $table = new xmldb_table('book_chapters');
+ $field = new xmldb_field('contentformat', XMLDB_TYPE_INTEGER, '4', null, XMLDB_NOTNULL, null, '0', 'content');
+
+ // Launch add field introformat
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+
+ $DB->set_field('book_chapters', 'contentformat', FORMAT_HTML, array());
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061705, 'book');
+ }
+
+ if ($oldversion < 2012061706) {
+ require_once("$CFG->dirroot/mod/book/db/upgradelib.php");
+
+ $sqlfrom = "FROM {book} b
+ JOIN {modules} m ON m.name = 'book'
+ JOIN {course_modules} cm ON (cm.module = m.id AND cm.instance = b.id)";
+
+ $count = $DB->count_records_sql("SELECT COUNT('x') $sqlfrom");
+
+ if ($rs = $DB->get_recordset_sql("SELECT b.id, b.course, cm.id AS cmid $sqlfrom ORDER BY b.course, b.id")) {
+
+ $pbar = new progress_bar('migratebookfiles', 500, true);
+
+ $i = 0;
+ foreach ($rs as $book) {
+ $i++;
+ upgrade_set_timeout(360); // set up timeout, may also abort execution
+ $pbar->update($i, $count, "Migrating book files - $i/$count.");
+
+ $context = context_module::instance($book->cmid);
+
+ mod_book_migrate_moddata_dir_to_legacy($book, $context, '/');
+
+ // remove dirs if empty
+ @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id/");
+ @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/book/");
+ @rmdir("$CFG->dataroot/$book->course/$CFG->moddata/");
+ @rmdir("$CFG->dataroot/$book->course/");
+ }
+ $rs->close();
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061706, 'book');
+ }
+
+ if ($oldversion < 2012061707) {
+ // Define field disableprinting to be dropped from book
+ $table = new xmldb_table('book');
+ $field = new xmldb_field('disableprinting');
+
+ // Conditionally launch drop field disableprinting
+ if ($dbman->field_exists($table, $field)) {
+ $dbman->drop_field($table, $field);
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061707, 'book');
+ }
+
+ if ($oldversion < 2012061708) {
+ unset_config('book_tocwidth');
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061708, 'book');
+ }
+
+ if ($oldversion < 2012061709) {
+ require_once("$CFG->dirroot/mod/book/db/upgradelib.php");
+
+ mod_book_migrate_all_areas();
+
+ upgrade_mod_savepoint(true, 2012061709, 'book');
+ }
+
+ if ($oldversion < 2012061710) {
+
+ // Define field revision to be added to book
+ $table = new xmldb_table('book');
+ $field = new xmldb_field('revision', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'customtitles');
+
+ // Conditionally launch add field revision
+ if (!$dbman->field_exists($table, $field)) {
+ $dbman->add_field($table, $field);
+ }
+
+ // book savepoint reached
+ upgrade_mod_savepoint(true, 2012061710, 'book');
+ }
+ // End of MDL-35297 "replayed" steps.
return true;
}
--- /dev/null
+<?php
+// This file is part of Book module for Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Book module upgrade related helper functions
+ *
+ * @package mod_book
+ * @copyright 2010 Petr Skoda {@link http://skodak.org}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * Migrate book files stored in moddata folders.
+ *
+ * Please note it was a big mistake to store the files there in the first place!
+ *
+ * @param stdClass $book
+ * @param stdClass $context
+ * @param string $path
+ * @return void
+ */
+function mod_book_migrate_moddata_dir_to_legacy($book, $context, $path) {
+ global $OUTPUT, $CFG;
+
+ $base = "$CFG->dataroot/$book->course/$CFG->moddata/book/$book->id";
+ $fulldir = $base.$path;
+
+ if (!is_dir($fulldir)) {
+ // does not exist
+ return;
+ }
+
+ $fs = get_file_storage();
+ $items = new DirectoryIterator($fulldir);
+
+ foreach ($items as $item) {
+ if ($item->isDot()) {
+ unset($item); // release file handle
+ continue;
+ }
+
+ if ($item->isLink()) {
+ // do not follow symlinks - they were never supported in moddata, sorry
+ unset($item); // release file handle
+ continue;
+ }
+
+ if ($item->isFile()) {
+ if (!$item->isReadable()) {
+ echo $OUTPUT->notification(" File not readable, skipping: ".$fulldir.$item->getFilename());
+ unset($item); // release file handle
+ continue;
+ }
+
+ $filepath = clean_param("/$CFG->moddata/book/$book->id".$path, PARAM_PATH);
+ $filename = clean_param($item->getFilename(), PARAM_FILE);
+
+ if ($filename === '') {
+ // unsupported chars, sorry
+ unset($item); // release file handle
+ continue;
+ }
+
+ if (textlib::strlen($filepath) > 255) {
+ echo $OUTPUT->notification(" File path longer than 255 chars, skipping: ".$fulldir.$item->getFilename());
+ unset($item); // release file handle
+ continue;
+ }
+
+ if (!$fs->file_exists($context->id, 'course', 'legacy', '0', $filepath, $filename)) {
+ $file_record = array('contextid'=>$context->id, 'component'=>'course', 'filearea'=>'legacy', 'itemid'=>0, 'filepath'=>$filepath, 'filename'=>$filename,
+ 'timecreated'=>$item->getCTime(), 'timemodified'=>$item->getMTime());
+ $fs->create_file_from_pathname($file_record, $fulldir.$item->getFilename());
+ }
+ $oldpathname = $fulldir.$item->getFilename();
+ unset($item); // release file handle
+ @unlink($oldpathname);
+
+ } else {
+ // migrate recursively all subdirectories
+ $oldpathname = $base.$item->getFilename().'/';
+ $subpath = $path.$item->getFilename().'/';
+ unset($item); // release file handle
+ mod_book_migrate_moddata_dir_to_legacy($book, $context, $subpath);
+ @rmdir($oldpathname); // deletes dir if empty
+ }
+ }
+ unset($items); // release file handles
+}
+
+/**
+ * Migrate legacy files in intro and chapters
+ * @return void
+ */
+function mod_book_migrate_all_areas() {
+ global $DB;
+
+ $rsbooks = $DB->get_recordset('book');
+ foreach($rsbooks as $book) {
+ upgrade_set_timeout(360); // set up timeout, may also abort execution
+ $cm = get_coursemodule_from_instance('book', $book->id);
+ $context = context_module::instance($cm->id);
+ mod_book_migrate_area($book, 'intro', 'book', $book->course, $context, 'mod_book', 'intro', 0);
+
+ $rschapters = $DB->get_recordset('book_chapters', array('bookid'=>$book->id));
+ foreach ($rschapters as $chapter) {
+ mod_book_migrate_area($chapter, 'content', 'book_chapters', $book->course, $context, 'mod_book', 'chapter', $chapter->id);
+ }
+ $rschapters->close();
+ }
+ $rsbooks->close();
+}
+
+/**
+ * Migrate one area, this should be probably part of moodle core...
+ *
+ * @param stdClass $record object to migrate files (book, chapter)
+ * @param string $field field in the record we are going to migrate
+ * @param string $table DB table containing the information to migrate
+ * @param int $courseid id of the course the book module belongs to
+ * @param context_module $context context of the book module
+ * @param string $component component to be used for the migrated files
+ * @param string $filearea filearea to be used for the migrated files
+ * @param int $itemid id to be used for the migrated files
+ * @return void
+ */
+function mod_book_migrate_area($record, $field, $table, $courseid, $context, $component, $filearea, $itemid) {
+ global $CFG, $DB;
+
+ $fs = get_file_storage();
+
+ foreach(array(get_site()->id, $courseid) as $cid) {
+ $matches = null;
+ $ooldcontext = context_course::instance($cid);
+ if (preg_match_all("|$CFG->wwwroot/file.php(\?file=)?/$cid(/[^\s'\"&\?#]+)|", $record->$field, $matches)) {
+ $file_record = array('contextid'=>$context->id, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid);
+ foreach ($matches[2] as $i=>$filepath) {
+ if (!$file = $fs->get_file_by_hash(sha1("/$ooldcontext->id/course/legacy/0".$filepath))) {
+ continue;
+ }
+ try {
+ if (!$newfile = $fs->get_file_by_hash(sha1("/$context->id/$component/$filearea/$itemid".$filepath))) {
+ $fs->create_file_from_storedfile($file_record, $file);
+ }
+ $record->$field = str_replace($matches[0][$i], '@@PLUGINFILE@@'.$filepath, $record->$field);
+ } catch (Exception $ex) {
+ // ignore problems
+ }
+ $DB->set_field($table, $field, $record->$field, array('id'=>$record->id));
+ }
+ }
+ }
+}
\ No newline at end of file
$string['chaptertitle'] = 'Chapter title';
$string['content'] = 'Content';
$string['subchapter'] = 'Subchapter';
+$string['nocontent'] = 'No content has been added to this book yet.';
$string['numbering'] = 'Chapter formatting';
$string['numbering_help'] = '* None - Chapter and subchapter titles have no formatting
* Numbers - Chapters and subchapter titles are numbered 1, 1.1, 1.2, 2, ...
* @return array of file_info instances
*/
public function get_children() {
+ return $this->get_filtered_children('*', false, true);
+ }
+
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
global $DB;
+ $params = array('contextid' => $this->context->id,
+ 'component' => 'mod_book',
+ 'filearea' => $this->filearea,
+ 'bookid' => $this->cm->instance);
+ $sql = 'SELECT DISTINCT bc.id, bc.pagenum
+ FROM {files} f, {book_chapters} bc
+ WHERE f.contextid = :contextid
+ AND f.component = :component
+ AND f.filearea = :filearea
+ AND bc.bookid = :bookid
+ AND bc.id = f.itemid';
+ if (!$returnemptyfolders) {
+ $sql .= ' AND filename <> :emptyfilename';
+ $params['emptyfilename'] = '.';
+ }
+ list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
+ $sql .= ' '.$sql2;
+ $params = array_merge($params, $params2);
+ if ($countonly === false) {
+ $sql .= ' ORDER BY bc.pagenum';
+ }
+ $rs = $DB->get_recordset_sql($sql, $params);
$children = array();
- $chapters = $DB->get_records('book_chapters', array('bookid'=>$this->cm->instance), 'pagenum', 'id, pagenum');
- foreach ($chapters as $itemid => $unused) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $itemid)) {
- $children[] = $child;
+ foreach ($rs as $record) {
+ if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $record->id)) {
+ if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
+ $children[] = $child;
+ }
+ }
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
}
}
+ $rs->close();
+ if ($countonly !== false) {
+ return count($children);
+ }
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
* @return file_info or null for root
// If data submitted, then process and store.
if ($mform->is_cancelled()) {
if (empty($chapter->id)) {
- redirect("/mod/book/view.php?id=$cm->id");
+ redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id");
} else {
- redirect("/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
+ redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
}
} else if ($data = $mform->get_data()) {
defined('MOODLE_INTERNAL') || die;
$module->component = 'mod_book'; // Full name of the plugin (used for diagnostics)
-$module->version = 2012061702; // The current module version (Date: YYYYMMDDXX)
+$module->version = 2012061710; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2012061700; // Requires this Moodle version
$module->cron = 0; // Period for cron to check this module (secs)
}
}
-if (!$chapterid or !$chapter = $DB->get_record('book_chapters', array('id'=>$chapterid, 'bookid'=>$book->id))) {
- print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
-}
+$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
-// chapter is hidden for students
-if ($chapter->hidden and !$viewhidden) {
- print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
+// No content in the book.
+if (!$chapterid) {
+ $PAGE->set_url('/mod/book/view.php', array('id' => $id));
+ notice(get_string('nocontent', 'mod_book'), $courseurl->out(false));
+}
+// Chapter doesnt exist or it is hidden for students
+if ((!$chapter = $DB->get_record('book_chapters', array('id' => $chapterid, 'bookid' => $book->id))) or ($chapter->hidden and !$viewhidden)) {
+ print_error('errorchapter', 'mod_book', $courseurl);
}
$PAGE->set_url('/mod/book/view.php', array('id'=>$id, 'chapterid'=>$chapterid));
//Enable the following three functions once core API issues have been addressed.
function display_search_field($value=0) {
- $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value)
- . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value)
- . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value);
- return $selectors;
+ $selectors = html_writer::select_time('days', 'f_'.$this->field->id.'_d', $value['timestamp'])
+ . html_writer::select_time('months', 'f_'.$this->field->id.'_m', $value['timestamp'])
+ . html_writer::select_time('years', 'f_'.$this->field->id.'_y', $value['timestamp']);
+ $datecheck = html_writer::checkbox('f_'.$this->field->id.'_z', 1, $value['usedate']);
+ $str = $selectors . ' ' . $datecheck . ' ' . get_string('usedate', 'data');
- //return print_date_selector('f_'.$this->field->id.'_d', 'f_'.$this->field->id.'_m', 'f_'.$this->field->id.'_y', $value, true);
+ return $str;
}
function generate_sql($tablealias, $value) {
$i++;
$name = "df_date_$i";
$varcharcontent = $DB->sql_compare_text("{$tablealias}.content");
- return array(" ({$tablealias}.fieldid = {$this->field->id} AND $varcharcontent = :$name) ", array($name=>$value));
+ return array(" ({$tablealias}.fieldid = {$this->field->id} AND $varcharcontent = :$name) ", array($name => $value['timestamp']));
}
function parse_search_field() {
-
$day = optional_param('f_'.$this->field->id.'_d', 0, PARAM_INT);
$month = optional_param('f_'.$this->field->id.'_m', 0, PARAM_INT);
$year = optional_param('f_'.$this->field->id.'_y', 0, PARAM_INT);
- if (!empty($day) && !empty($month) && !empty($year)) {
- return make_timestamp($year, $month, $day, 12, 0, 0, 0, false);
- }
- else {
+ $usedate = optional_param('f_'.$this->field->id.'_z', 0, PARAM_INT);
+ $data = array();
+ if (!empty($day) && !empty($month) && !empty($year) && $usedate == 1) {
+ $data['timestamp'] = make_timestamp($year, $month, $day, 12, 0, 0, 0, false);
+ $data['usedate'] = 1;
+ return $data;
+ } else {
return 0;
}
-
}
function update_content($recordid, $value, $name='') {
The field enclosure is a character that surrounds each field in each record. It can normally be left unset.';
$string['uploadrecords_link'] = 'mod/data/import';
$string['url'] = 'Url';
+$string['usedate'] = 'Include in search.';
$string['usestandard'] = 'Use a preset';
$string['usestandard_help'] = 'To use a preset available to the whole site, select it from the list. (If you have added a preset to the list using the save as preset feature then you have the option of deleting it.)';
$string['viewfromdate'] = 'Read only from';
/**
* Get all of the record ids from a database activity.
*
- * @param int $dataid The dataid of the database module.
- * @return array $idarray An array of record ids
+ * @param int $dataid The dataid of the database module.
+ * @param object $selectdata Contains an additional sql statement for the
+ * where clause for group and approval fields.
+ * @param array $params Parameters that coincide with the sql statement.
+ * @return array $idarray An array of record ids
*/
-function data_get_all_recordids($dataid) {
+function data_get_all_recordids($dataid, $selectdata = '', $params = null) {
global $DB;
- $initsql = 'SELECT c.recordid
- FROM {data_fields} f,
- {data_content} c
- WHERE f.dataid = :dataid
- AND f.id = c.fieldid
- GROUP BY c.recordid';
- $initrecord = $DB->get_recordset_sql($initsql, array('dataid' => $dataid));
+ $initsql = 'SELECT r.id
+ FROM {data_records} r
+ WHERE r.dataid = :dataid';
+ if ($selectdata != '') {
+ $initsql .= $selectdata;
+ $params = array_merge(array('dataid' => $dataid), $params);
+ } else {
+ $params = array('dataid' => $dataid);
+ }
+ $initsql .= ' GROUP BY r.id';
+ $initrecord = $DB->get_recordset_sql($initsql, $params);
$idarray = array();
foreach ($initrecord as $data) {
- $idarray[] = $data->recordid;
+ $idarray[] = $data->id;
}
// Close the record set and free up resources.
$initrecord->close();
} else {
list($insql, $inparam) = $DB->get_in_or_equal(array('-1'), SQL_PARAMS_NAMED);
}
- $nestfromsql .= ' AND c.recordid ' . $insql . $groupsql;
- $nestfromsql = "$nestfromsql $selectdata";
+ $nestfromsql .= ' AND c.recordid ' . $insql . $selectdata . $groupsql;
$sqlselect['sql'] = "$nestselectsql $nestfromsql $sortorder";
$sqlselect['params'] = $inparam;
return $sqlselect;
* @return array of file_info instances
*/
public function get_children() {
+ return $this->get_filtered_children('*', false, true);
+ }
+
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
global $DB;
+ $params = array('contextid' => $this->context->id,
+ 'component' => $this->component,
+ 'filearea' => $this->filearea);
+ $sql = 'SELECT DISTINCT itemid
+ FROM {files}
+ WHERE contextid = :contextid
+ AND component = :component
+ AND filearea = :filearea';
+ if (!$returnemptyfolders) {
+ $sql .= ' AND filename <> :emptyfilename';
+ $params['emptyfilename'] = '.';
+ }
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $sql .= ' '.$sql2;
+ $params = array_merge($params, $params2);
+ if ($countonly === false) {
+ $sql .= ' ORDER BY itemid DESC';
+ }
+ $rs = $DB->get_recordset_sql($sql, $params);
$children = array();
- $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'component' => $this->component,
- 'filearea' => $this->filearea), 'itemid DESC', "DISTINCT itemid");
- foreach ($itemids as $itemid => $unused) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $itemid)) {
+ foreach ($rs as $record) {
+ if ($child = $this->browser->get_file_info($this->context, 'mod_data', $this->filearea, $record->itemid)) {
$children[] = $child;
}
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
+ }
+ }
+ $rs->close();
+ if ($countonly !== false) {
+ return count($children);
}
-
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
*
id,userid,groupid,dataid,timecreated,timemodified,approved
1,1,0,1,1234567891,1234567892,1
-2,2,0,1,1234567891,1234567892,1
-3,3,0,1,1234567891,1234567892,1
-4,4,0,1,1234567891,1234567892,1
-5,5,0,1,1234567891,1234567892,1
-6,6,0,1,1234567891,1234567892,1
+2,2,1,1,1234567891,1234567892,1
+3,3,2,1,1234567891,1234567892,1
+4,4,1,1,1234567891,1234567892,1
+5,5,1,1,1234567891,1234567892,1
+6,6,2,1,1234567891,1234567892,1
7,7,0,1,1234567891,1234567892,1
-8,8,0,1,1234567891,1234567892,1
-9,9,0,1,1234567891,1234567892,1
-10,10,0,1,1234567891,1234567892,1
-11,11,0,1,1234567891,1234567892,1
-12,12,0,1,1234567891,1234567892,1
-13,13,0,1,1234567891,1234567892,1
+8,8,2,1,1234567891,1234567892,1
+9,9,1,1,1234567891,1234567892,1
+10,10,1,1,1234567891,1234567892,1
+11,11,1,1,1234567891,1234567892,1
+12,12,2,1,1234567891,1234567892,1
+13,13,2,1,1234567891,1234567892,1
14,14,0,1,1234567891,1234567892,1
-15,15,0,1,1234567891,1234567892,1
+15,15,2,1,1234567891,1234567892,1
16,16,0,1,1234567891,1234567892,1
-17,17,0,1,1234567891,1234567892,1
-18,18,0,1,1234567891,1234567892,1
+17,17,1,1,1234567891,1234567892,1
+18,18,2,1,1234567891,1234567892,1
19,19,0,1,1234567891,1234567892,1
-20,20,0,1,1234567891,1234567892,1
+20,20,1,1,1234567891,1234567892,1
21,21,0,1,1234567891,1234567892,1
-22,22,0,1,1234567891,1234567892,1
+22,22,2,1,1234567891,1234567892,1
23,23,0,1,1234567891,1234567892,1
-24,24,0,1,1234567891,1234567892,1
-25,25,0,1,1234567891,1234567892,1
+24,24,2,1,1234567891,1234567892,1
+25,25,2,1,1234567891,1234567892,1
26,26,0,1,1234567891,1234567892,1
-27,27,0,1,1234567891,1234567892,1
-28,28,0,1,1234567891,1234567892,1
+27,27,1,1,1234567891,1234567892,1
+28,28,2,1,1234567891,1234567892,1
29,29,0,1,1234567891,1234567892,1
-30,30,0,1,1234567891,1234567892,1
+30,30,2,1,1234567891,1234567892,1
31,31,0,1,1234567891,1234567892,1
-32,32,0,1,1234567891,1234567892,1
-33,33,0,1,1234567891,1234567892,1
-34,34,0,1,1234567891,1234567892,1
-35,35,0,1,1234567891,1234567892,1
+32,32,1,1,1234567891,1234567892,1
+33,33,1,1,1234567891,1234567892,1
+34,34,2,1,1234567891,1234567892,1
+35,35,1,1,1234567891,1234567892,1
36,36,0,1,1234567891,1234567892,1
37,37,0,1,1234567891,1234567892,1
-38,38,0,1,1234567891,1234567892,1
-39,39,0,1,1234567891,1234567892,1
-40,40,0,1,1234567891,1234567892,1
+38,38,2,1,1234567891,1234567892,1
+39,39,1,1,1234567891,1234567892,1
+40,40,1,1,1234567891,1234567892,1
41,41,0,1,1234567891,1234567892,1
-42,42,0,1,1234567891,1234567892,1
+42,42,1,1,1234567891,1234567892,1
43,43,0,1,1234567891,1234567892,1
-44,44,0,1,1234567891,1234567892,1
+44,44,1,1,1234567891,1234567892,1
45,45,0,1,1234567891,1234567892,1
46,46,0,1,1234567891,1234567892,1
-47,47,0,1,1234567891,1234567892,1
+47,47,1,1,1234567891,1234567892,1
48,48,0,1,1234567891,1234567892,1
49,49,0,1,1234567891,1234567892,1
-50,50,0,1,1234567891,1234567892,1
+50,50,1,1,1234567891,1234567892,1
51,51,0,1,1234567891,1234567892,1
52,52,0,1,1234567891,1234567892,1
-53,53,0,1,1234567891,1234567892,1
-54,54,0,1,1234567891,1234567892,1
+53,53,1,1,1234567891,1234567892,1
+54,54,1,1,1234567891,1234567892,1
55,55,0,1,1234567891,1234567892,1
-56,56,0,1,1234567891,1234567892,1
-57,57,0,1,1234567891,1234567892,1
-58,58,0,1,1234567891,1234567892,1
-59,59,0,1,1234567891,1234567892,1
-60,60,0,1,1234567891,1234567892,1
+56,56,2,1,1234567891,1234567892,1
+57,57,2,1,1234567891,1234567892,1
+58,58,2,1,1234567891,1234567892,1
+59,59,1,1,1234567891,1234567892,1
+60,60,1,1,1234567891,1234567892,1
61,61,0,1,1234567891,1234567892,1
-62,62,0,1,1234567891,1234567892,1
+62,62,2,1,1234567891,1234567892,1
63,63,0,1,1234567891,1234567892,1
64,64,0,1,1234567891,1234567892,1
-65,65,0,1,1234567891,1234567892,1
-66,66,0,1,1234567891,1234567892,1
+65,65,1,1,1234567891,1234567892,1
+66,66,1,1,1234567891,1234567892,1
67,67,0,1,1234567891,1234567892,1
68,68,0,1,1234567891,1234567892,1
-69,69,0,1,1234567891,1234567892,1
-70,70,0,1,1234567891,1234567892,1
+69,69,2,1,1234567891,1234567892,1
+70,70,2,1,1234567891,1234567892,1
71,71,0,1,1234567891,1234567892,1
-72,72,0,1,1234567891,1234567892,1
-73,73,0,1,1234567891,1234567892,1
+72,72,1,1,1234567891,1234567892,1
+73,73,1,1,1234567891,1234567892,1
74,74,0,1,1234567891,1234567892,1
75,75,0,1,1234567891,1234567892,1
-76,76,0,1,1234567891,1234567892,1
-77,77,0,1,1234567891,1234567892,1
+76,76,2,1,1234567891,1234567892,1
+77,77,2,1,1234567891,1234567892,1
78,78,0,1,1234567891,1234567892,1
-79,79,0,1,1234567891,1234567892,1
-80,80,0,1,1234567891,1234567892,1
+79,79,1,1,1234567891,1234567892,1
+80,80,1,1,1234567891,1234567892,1
81,81,0,1,1234567891,1234567892,1
-82,82,0,1,1234567891,1234567892,1
-83,83,0,1,1234567891,1234567892,1
-84,84,0,1,1234567891,1234567892,1
-85,85,0,1,1234567891,1234567892,1
+82,82,1,1,1234567891,1234567892,1
+83,83,1,1,1234567891,1234567892,1
+84,84,1,1,1234567891,1234567892,1
+85,85,1,1,1234567891,1234567892,1
86,86,0,1,1234567891,1234567892,1
87,87,0,1,1234567891,1234567892,1
88,88,0,1,1234567891,1234567892,1
-89,89,0,1,1234567891,1234567892,1
-90,90,0,1,1234567891,1234567892,1
-91,91,0,1,1234567891,1234567892,1
-92,92,0,1,1234567891,1234567892,1
-93,93,0,1,1234567891,1234567892,1
-94,94,0,1,1234567891,1234567892,1
-95,95,0,1,1234567891,1234567892,1
-96,96,0,1,1234567891,1234567892,1
-97,97,0,1,1234567891,1234567892,1
-98,98,0,1,1234567891,1234567892,1
-99,99,0,1,1234567891,1234567892,1
-100,100,0,1,1234567891,1234567892,1
+89,89,1,1,1234567891,1234567892,1
+90,90,1,1,1234567891,1234567892,0
+91,91,2,1,1234567891,1234567892,0
+92,92,0,1,1234567891,1234567892,0
+93,93,2,1,1234567891,1234567892,0
+94,94,1,1,1234567891,1234567892,0
+95,95,1,1,1234567891,1234567892,0
+96,96,1,1,1234567891,1234567892,0
+97,97,0,1,1234567891,1234567892,0
+98,98,1,1,1234567891,1234567892,0
+99,99,2,1,1234567891,1234567892,0
+100,100,0,1,1234567891,1234567892,0
*/
public $datarecordcount = 100;
+ /**
+ * @var int $groupdatarecordcount The number of records in the database in groups 0 and 1.
+ */
+ public $groupdatarecordcount = 75;
+
/**
* @var array $datarecordset Expected record IDs.
*/
*/
public $finalrecord = array();
+ /**
+ * @var int $approvedatarecordcount The number of approved records in the database.
+ */
+ public $approvedatarecordcount = 89;
+
/**
* Set up function. In this instance we are setting up database
* records to be used in the unit tests.
* Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
* to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
* takes that information and does a search on the database, returning a record.
+ *
+ * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to
+ * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed
+ * from the total so we should only have 75 records total.
+ *
+ * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to
+ * display the records that have been approved. In this record set we have 89 approved records.
*/
function test_advanced_search_sql_section() {
global $DB;
$allparams = array_merge($html['params'], array('dataid' => $this->recorddata->id));
$records = $DB->get_records_sql($html['sql'], $allparams);
$this->assertEquals($records, $this->finalrecord);
+
+ // Test 5
+ $groupsql = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
+ $params = array('currentgroup' => 1);
+ $recordids = data_get_all_recordids($this->recorddata->id, $groupsql, $params);
+ $this->assertEquals($this->groupdatarecordcount, count($recordids));
+
+ // Test 6
+ $approvesql = ' AND r.approved=1 ';
+ $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params);
+ $this->assertEquals($this->approvedatarecordcount, count($recordids));
}
}
groups_print_activity_menu($cm, $returnurl);
$currentgroup = groups_get_activity_group($cm);
$groupmode = groups_get_activity_groupmode($cm);
+ // If a student is not part of a group and seperate groups is enabled, we don't
+ // want them seeing all records.
+ if ($currentgroup == 0 && $groupmode == 1 && !has_capability('mod/data:manageentries', $context)) {
+ $canviewallrecords = false;
+ } else {
+ $canviewallrecords = true;
+ }
// detect entries not approved yet and show hint instead of not found error
if ($record and $data->approval and !$record->approved and $record->userid != $USER->id and !has_capability('mod/data:manageentries', $context)) {
$groupselect = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
$params['currentgroup'] = $currentgroup;
} else {
- $groupselect = ' ';
+ if ($canviewallrecords) {
+ $groupselect = ' ';
+ } else {
+ // If separate groups are enabled and the user isn't in a group or
+ // a teacher, manager, admin etc, then just show them entries for 'All participants'.
+ $groupselect = " AND r.groupid = 0";
+ }
}
// Init some variables to be used by advanced search
$sqlmax = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
$allparams = array_merge($params, $advparams);
- $recordids = data_get_all_recordids($data->id);
+ // Provide initial sql statements and parameters to reduce the number of total records.
+ $selectdata = $groupselect . $approveselect;
+ $initialparams = array();
+ if ($currentgroup) {
+ $initialparams['currentgroup'] = $params['currentgroup'];
+ }
+ if (!$approvecap && $data->approval && isloggedin()) {
+ $initialparams['myid1'] = $params['myid1'];
+ }
+
+ $recordids = data_get_all_recordids($data->id, $selectdata, $initialparams);
$newrecordids = data_get_advance_search_ids($recordids, $search_array, $data->id);
$totalcount = count($newrecordids);
- $selectdata = $groupselect . $approveselect;
if (!empty($advanced)) {
$advancedsearchsql = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
* @return array of file_info instances
*/
public function get_children() {
+ return $this->get_filtered_children('*', false, true);
+ }
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
global $DB;
+ $params = array('contextid' => $this->context->id,
+ 'component' => $this->component,
+ 'filearea' => $this->filearea);
+ $sql = 'SELECT DISTINCT itemid
+ FROM {files}
+ WHERE contextid = :contextid
+ AND component = :component
+ AND filearea = :filearea';
+ if (!$returnemptyfolders) {
+ $sql .= ' AND filename <> :emptyfilename';
+ $params['emptyfilename'] = '.';
+ }
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $sql .= ' '.$sql2;
+ $params = array_merge($params, $params2);
+ if ($countonly !== false) {
+ $sql .= ' ORDER BY itemid DESC';
+ }
+ $rs = $DB->get_recordset_sql($sql, $params);
$children = array();
- $itemids = $DB->get_records('files', array('contextid' => $this->context->id, 'component' => $this->component,
- 'filearea' => $this->filearea), 'itemid DESC', "DISTINCT itemid");
- foreach ($itemids as $itemid => $unused) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_forum', $this->filearea, $itemid)) {
+ foreach ($rs as $record) {
+ if (($child = $this->browser->get_file_info($this->context, 'mod_forum', $this->filearea, $record->itemid))
+ && ($returnemptyfolders || $child->count_non_empty_children($extensions))) {
$children[] = $child;
}
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
+ }
+ }
+ $rs->close();
+ if ($countonly !== false) {
+ return count($children);
}
-
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
*
/** Unknown Styles ??? */
#email .unsubscribelink {margin-top:20px;}
+
+
+/* Forumpost unread
+-------------------------*/
+#page-mod-forum-view .unread,
+.forumpost.unread .row.header,
+.path-course-view .unread,
+span.unread {
+ background-color: #FFD;
+}
+.forumpost.unread .row.header {
+ border-bottom: 1px solid #DDD;
+}
\ No newline at end of file
* @return array of file_info instances
*/
public function get_children() {
- global $DB;
+ return $this->get_filtered_children('*', false, true);
+ }
- $sql = "SELECT DISTINCT f.itemid, ge.concept
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
+ global $DB;
+ $sql = 'SELECT DISTINCT f.itemid, ge.concept
FROM {files} f
- JOIN {modules} m ON (m.name = 'glossary' AND m.visible = 1)
- JOIN {course_modules} cm ON (cm.module = m.id AND cm.id = ?)
+ JOIN {modules} m ON (m.name = :modulename AND m.visible = 1)
+ JOIN {course_modules} cm ON (cm.module = m.id AND cm.id = :instanceid)
JOIN {glossary} g ON g.id = cm.instance
JOIN {glossary_entries} ge ON (ge.glossaryid = g.id AND ge.id = f.itemid)
- WHERE f.contextid = ? AND f.component = ? AND f.filearea = ?
- ORDER BY ge.concept, f.itemid";
- $params = array($this->context->instanceid, $this->context->id, $this->component, $this->filearea);
+ WHERE f.contextid = :contextid
+ AND f.component = :component
+ AND f.filearea = :filearea';
+ $params = array(
+ 'modulename' => 'glossary',
+ 'instanceid' => $this->context->instanceid,
+ 'contextid' => $this->context->id,
+ 'component' => $this->component,
+ 'filearea' => $this->filearea);
+ if (!$returnemptyfolders) {
+ $sql .= ' AND f.filename <> :emptyfilename';
+ $params['emptyfilename'] = '.';
+ }
+ list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
+ $sql .= ' '.$sql2;
+ $params = array_merge($params, $params2);
+ if ($countonly !== false) {
+ $sql .= ' ORDER BY ge.concept, f.itemid';
+ }
$rs = $DB->get_recordset_sql($sql, $params);
$children = array();
- foreach ($rs as $file) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $file->itemid)) {
+ foreach ($rs as $record) {
+ if ($child = $this->browser->get_file_info($this->context, 'mod_glossary', $this->filearea, $record->itemid)) {
$children[] = $child;
}
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
+ }
}
$rs->close();
-
+ if ($countonly !== false) {
+ return count($children);
+ }
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
*
* @return array of file_info instances
*/
public function get_children() {
+ return $this->get_filtered_children('*', false, true);
+ }
+
+ /**
+ * Help function to return files matching extensions or their count
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @param bool|int $countonly if false returns the children, if an int returns just the
+ * count of children but stops counting when $countonly number of children is reached
+ * @param bool $returnemptyfolders if true returns items that don't have matching files inside
+ * @return array|int array of file_info instances or the count
+ */
+ private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
global $DB;
+ $params = array('contextid' => $this->context->id,
+ 'component' => 'mod_imscp',
+ 'filearea' => $this->filearea);
+ $sql = 'SELECT DISTINCT itemid
+ FROM {files}
+ WHERE contextid = :contextid
+ AND component = :component
+ AND filearea = :filearea';
+ if (!$returnemptyfolders) {
+ $sql .= ' AND filename <> :emptyfilename';
+ $params['emptyfilename'] = '.';
+ }
+ list($sql2, $params2) = $this->build_search_files_sql($extensions);
+ $sql .= ' '.$sql2;
+ $params = array_merge($params, $params2);
+ if ($countonly !== false) {
+ $sql .= ' ORDER BY itemid';
+ }
+ $rs = $DB->get_recordset_sql($sql, $params);
$children = array();
- $itemids = $DB->get_records('files', array('contextid'=>$this->context->id, 'component'=>'mod_imscp', 'filearea'=>$this->filearea), 'itemid', "DISTINCT itemid");
- foreach ($itemids as $itemid=>$unused) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_imscp', $this->filearea, $itemid)) {
+ foreach ($rs as $record) {
+ if ($child = $this->browser->get_file_info($this->context, 'mod_imscp', $this->filearea, $record->itemid)) {
$children[] = $child;
+ if ($countonly !== false && count($children) >= $countonly) {
+ break;
+ }
}
}
+ $rs->close();
+ if ($countonly !== false) {
+ return count($children);
+ }
return $children;
}
+ /**
+ * Returns list of children which are either files matching the specified extensions
+ * or folders that contain at least one such file.
+ *
+ * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
+ * @return array of file_info instances
+ */
+ public function get_non_empty_children($extensions = '*') {
+ return $this->get_filtered_children($extensions, false);
+ }
+
+ /**
+ * Returns the number of children which are either files matching the specified extensions
+ * or folders containing at least one such file.
+ *
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param int $limit stop counting after at least $limit non-empty children are found
+ * @return int
+ */
+ public function count_non_empty_children($extensions = '*', $limit = 1) {
+ return $this->get_filtered_children($extensions, $limit);
+ }
+
/**
* Returns parent file_info instance
* @return file_info or null for root
+++ /dev/null
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * This is a very rough importer for powerpoint slides
- * Export a powerpoint presentation with powerpoint as html pages
- * Do it with office 2002 (I think?) and no special settings
- * Then zip the directory with all of the html pages
- * and the zip file is what you want to upload
- *
- * The script supports book and lesson.
- *
- * @package mod
- * @subpackage lesson
- * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-
-/** include required files */
-require_once("../../config.php");
-require_once($CFG->dirroot.'/mod/lesson/locallib.php');
-require_once($CFG->dirroot.'/mod/lesson/importpptlib.php');
-
-$id = required_param('id', PARAM_INT); // Course Module ID
-$pageid = optional_param('pageid', '', PARAM_INT); // Page ID
-
-$url = new moodle_url('/mod/lesson/importppt.php', array('id'=>$id));
-if ($pageid !== '') {
- $url->param('pageid', $pageid);
-}
-$PAGE->set_url($url);
-
-$cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST);;
-$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
-$lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST));
-
-$modname = 'lesson';
-$mod = $cm;
-require_login($course, false, $cm);
-
-require_login($course, false, $cm);
-$context = get_context_instance(CONTEXT_MODULE, $cm->id);
-require_capability('mod/lesson:edit', $context);
-
-$strimportppt = get_string("importppt", "lesson");
-$strlessons = get_string("modulenameplural", "lesson");
-
-$data = new stdClass;
-$data->id = $cm->id;
-$data->pageid = $pageid;
-$mform = new lesson_importppt_form();
-$mform->set_data($data);
-
-if ($data = $mform->get_data()) {
- $manager = lesson_page_type_manager::get($lesson);
- if (!$filename = $mform->get_new_filename('pptzip')) {
- print_error('invalidfile', 'lesson');
- }
- if (!$package = $mform->save_stored_file('pptzip', $context->id, 'mod_lesson', 'ppt_imports', $lesson->id, '/', $filename, true)) {
- print_error('unabletosavefile', 'lesson');
- }
- // extract package content
- $packer = get_file_packer('application/zip');
- $package->extract_to_storage($packer, $context->id, 'mod_lesson', 'imported_files', $lesson->id, '/');
-
- $fs = get_file_storage();
- if ($files = $fs->get_area_files($context->id, 'mod_lesson', 'imported_files', $lesson->id)) {
-
- $pages = array();
- foreach ($files as $key=>$file) {
- if ($file->get_mimetype() != 'text/html') {
- continue;
- }
- $filenameinfo = pathinfo($file->get_filepath().$file->get_filename());
-
- $page = new stdClass;
- $page->title = '';
- $page->contents = array();
- $page->images = array();
- $page->source = $filenameinfo['basename'];
-
- $string = strip_tags($file->get_content(),'<div><img>');
- $imgs = array();
- preg_match_all("/<img[^>]*(src\=\"(".$filenameinfo['filename']."\_image[^>^\"]*)\"[^>]*)>/i", $string, $imgs);
- foreach ($imgs[2] as $img) {
- $imagename = basename($img);
- foreach ($files as $file) {
- if ($imagename === $file->get_filename()) {
- $page->images[] = clone($file);
- }
- }
- }
-
- $matches = array();
- // this will look for a non nested tag that is closed
- // want to allow <b><i>(maybe more) tags but when we do that
- // the preg_match messes up.
- preg_match_all("/(<([\w]+)[^>]*>)([^<\\2>]*)(<\/\\2>)/", $string, $matches);
- $countmatches = count($matches[1]);
- for($i = 0; $i < $countmatches; $i++) { // go through all of our div matches
-
- $class = lesson_importppt_isolate_class($matches[1][$i]); // first step in isolating the class
-
- // check for any static classes
- switch ($class) {
- case 'T': // class T is used for Titles
- $page->title = $matches[3][$i];
- break;
- case 'B': // I would guess that all bullet lists would start with B then go to B1, B2, etc
- case 'B1': // B1-B4 are just insurance, should just hit B and all be taken care of
- case 'B2':
- case 'B3':
- case 'B4':
- $page->contents[] = lesson_importppt_build_list($matches, '<ul>', $i, 0); // this is a recursive function that will grab all the bullets and rebuild the list in html
- break;
- default:
- if ($matches[3][$i] != ' ') { // odd crap generated... sigh
- if (substr($matches[3][$i], 0, 1) == ':') { // check for leading : ... hate MS ...
- $page->contents[] = substr($matches[3][$i], 1); // get rid of :
- } else {
- $page->contents[] = $matches[3][$i];
- }
- }
- break;
- }
- }
- $pages[] = $page;
- }
-
- $branchtables = lesson_create_objects($pages, $lesson->id);
-
- // first set up the prevpageid and nextpageid
- if (empty($pageid)) { // adding it to the top of the lesson
- $prevpageid = 0;
- // get the id of the first page. If not found, then no pages in the lesson
- if (!$nextpageid = $DB->get_field('lesson_pages', 'id', array('prevpageid' => 0, 'lessonid' => $lesson->id))) {
- $nextpageid = 0;
- }
- } else {
- // going after an actual page
- $prevpageid = $pageid;
- $nextpageid = $DB->get_field('lesson_pages', 'nextpageid', array('id' => $pageid));
- }
-
- foreach ($branchtables as $branchtable) {
-
- // set the doubly linked list
- $branchtable->page->nextpageid = $nextpageid;
- $branchtable->page->prevpageid = $prevpageid;
-
- // insert the page
- $id = $DB->insert_record('lesson_pages', $branchtable->page);
-
- if (!empty($branchtable->page->images)) {
- $changes = array('contextid'=>$context->id, 'component'=>'mod_lesson', 'filearea'=>'page_contents', 'itemid'=>$id, 'timemodified'=>time());
- foreach ($branchtable->page->images as $image) {
- $fs->create_file_from_storedfile($changes, $image);
- }
- }
-
- // update the link of the page previous to the one we just updated
- if ($prevpageid != 0) { // if not the first page
- $DB->set_field("lesson_pages", "nextpageid", $id, array("id" => $prevpageid));
- }
-
- // insert the answers
- foreach ($branchtable->answers as $answer) {
- $answer->pageid = $id;
- $DB->insert_record('lesson_answers', $answer);
- }
-
- $prevpageid = $id;
- }
-
- // all done with inserts. Now check to update our last page (this is when we import between two lesson pages)
- if ($nextpageid != 0) { // if the next page is not the end of lesson
- $DB->set_field("lesson_pages", "prevpageid", $id, array("id" => $nextpageid));
- }
- }
-
- // Remove all unzipped files!
- $fs->delete_area_files($context->id, 'mod_lesson', 'imported_files', $lesson->id);
-
- redirect("$CFG->wwwroot/mod/$modname/view.php?id=$cm->id", get_string('pptsuccessfullimport', 'lesson'), 5);
-}
-
-$PAGE->navbar->add($strimportppt);
-$PAGE->set_title($strimportppt);
-$PAGE->set_heading($strimportppt);
-echo $OUTPUT->header();
-
-/// Print upload form
-echo $OUTPUT->heading_with_help($strimportppt, 'importppt', 'lesson');
-echo $OUTPUT->box_start('generalbox boxaligncenter');
-$mform->display();
-echo $OUTPUT->box_end();
-echo $OUTPUT->footer();
+++ /dev/null
-<?php
-
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Contains functions used by importppt.php that naturally pertain to importing
- * powerpoint presentations into the lesson module
- *
- * @package mod
- * @subpackage lesson
- * @copyright 2009 Sam Hemelryk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- **/
-
-defined('MOODLE_INTERNAL') || die();
-
-/**
- * A recursive function to build a html list
- *
- * @param array $matches
- * @param string $list
- * @param int $i
- * @param int $depth
- * @return string
- */
-function lesson_importppt_build_list(array &$matches, $list, &$i, $depth) {
- while($i < count($matches[1])) {
-
- $class = lesson_importppt_isolate_class($matches[1][$i]);
-
- if (strstr($class, 'B')) { // make sure we are still working with bullet classes
- if ($class == 'B') {
- $this_depth = 0; // calling class B depth 0
- } else {
- // set the depth number. So B1 is depth 1 and B2 is depth 2 and so on
- $this_depth = substr($class, 1);
- if (!is_numeric($this_depth)) {
- print_error('invalidnum');
- }
- }
- if ($this_depth < $depth) {
- // we are moving back a level in the nesting
- break;
- }
- if ($this_depth > $depth) {
- // we are moving in a lvl in nesting
- $list .= '<ul>';
- $list = lesson_importppt_build_list($matches, $list, $i, $this_depth);
- // once we return back, should go to the start of the while
- continue;
- }
- // no depth changes, so add the match to our list
- if ($cleanstring = lesson_importppt_clean_text($matches[3][$i])) {
- $list .= '<li>'.lesson_importppt_clean_text($matches[3][$i]).'</li>';
- }
- $i++;
- } else {
- // not a B class, so get out of here...
- break;
- }
- }
- // end the list and return it
- $list .= '</ul>';
- return $list;
-
-}
-
-/**
- * Given an html tag, this function will
- *
- * @param string $string
- * @return string
- */
-function lesson_importppt_isolate_class($string) {
- if($class = strstr($string, 'class=')) { // first step in isolating the class
- $class = substr($class, strpos($class, '=')+1); // this gets rid of <div blawblaw class= there are no "" or '' around the class name ...sigh...
- if (strstr($class, ' ')) {
- // spaces found, so cut off everything off after the first space
- return substr($class, 0, strpos($class, ' '));
- } else {
- // no spaces so nothing else in the div tag, cut off the >
- return substr($class, 0, strpos($class, '>'));
- }
- } else {
- // no class defined in the tag
- return '';
- }
-}
-
-/**
- * This function strips off the random chars that ppt puts infront of bullet lists
- *
- * @param string $string
- * @return string
- */
-function lesson_importppt_clean_text($string) {
- $chop = 1; // default: just a single char infront of the content
-
- // look for any other crazy things that may be infront of the content
- if (strstr($string, '<') and strpos($string, '<') == 0) { // look for the < in the sting and make sure it is in the front
- $chop = 4; // increase the $chop
- }
- // may need to add more later....
-
- $string = substr($string, $chop);
-
- if ($string != ' ') {
- return $string;
- } else {
- return false;
- }
-}
-
-/**
- * Creates objects an object with the page and answers that are to be inserted into the database
- *
- * @param array $pageobjects
- * @param int $lessonid
- * @return array
- */
-function lesson_create_objects($pageobjects, $lessonid) {
-
- $branchtables = array();
- $branchtable = new stdClass;
-
- // all pages have this info
- $page = new stdClass();
- $page->lessonid = $lessonid;
- $page->prevpageid = 0;
- $page->nextpageid = 0;
- $page->qtype = LESSON_PAGE_BRANCHTABLE;
- $page->qoption = 0;
- $page->layout = 1;
- $page->display = 1;
- $page->timecreated = time();
- $page->timemodified = 0;
-
- // all answers are the same
- $answer = new stdClass();
- $answer->lessonid = $lessonid;
- $answer->jumpto = LESSON_NEXTPAGE;
- $answer->grade = 0;
- $answer->score = 0;
- $answer->flags = 0;
- $answer->timecreated = time();
- $answer->timemodified = 0;
- $answer->answer = "Next";
- $answer->response = "";
-
- $answers[] = clone($answer);
-
- $answer->jumpto = LESSON_PREVIOUSPAGE;
- $answer->answer = "Previous";
-
- $answers[] = clone($answer);
-
- $branchtable->answers = $answers;
-
- $i = 1;
-
- foreach ($pageobjects as $pageobject) {
- if ($pageobject->title == '') {
- $page->title = "Page $i"; // no title set so make a generic one
- } else {
- $page->title = $pageobject->title;
- }
- $page->contents = '';
-
- // nab all the images first
- $page->images = $pageobject->images;
- foreach ($page->images as $image) {
- $imagetag = '<img src="@@PLUGINFILE@@'.$image->get_filepath().$image->get_filename().'" title="'.$image->get_filename().'" />';
- $imagetag = str_replace("\n", '', $imagetag);
- $imagetag = str_replace("\r", '', $imagetag);
- $imagetag = str_replace("'", '"', $imagetag); // imgstyle
- $page->contents .= $imagetag;
- }
- // go through the contents array and put <p> tags around each element and strip out \n which I have found to be unneccessary
- foreach ($pageobject->contents as $content) {
- $content = str_replace("\n", '', $content);
- $content = str_replace("\r", '', $content);
- $content = str_replace(' ', '', $content); // puts in returns?
- $content = '<p>'.$content.'</p>';
- $page->contents .= $content;
- }
-
- $branchtable->page = clone($page); // add the page
- $branchtables[] = clone($branchtable); // add it all to our array
- $i++;
- }
-
- return $branchtables;
-}
-
-/**
- * Form displayed to the user asking them to select a file to upload
- *
- * @copyright 2009 Sam Hemelryk
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class lesson_importppt_form extends moodleform {
-
- public function definition() {
- global $COURSE;
-
- $mform = $this->_form;
-
- $mform->addElement('hidden', 'id');
- $mform->setType('id', PARAM_INT);
-
- $mform->addElement('hidden', 'pageid');
- $mform->setType('pageid', PARAM_INT);
-
- $filepickeroptions = array();
- $filepickeroptions['filetypes'] = array('*.zip');
- $filepickeroptions['maxbytes'] = $COURSE->maxbytes;
- $mform->addElement('filepicker', 'pptzip', get_string('upload'), null, $filepickeroptions);
- $mform->addRule('pptzip', null, 'required', null, 'client');
-
- $this->add_action_buttons(null, get_string("uploadthisfile"));
- }
-
-}
\ No newline at end of file
$importquestionsurl = new moodle_url('/mod/lesson/import.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid));
$links[] = html_writer::link($importquestionsurl, get_string('importquestions', 'lesson'));
- $importppturl = new moodle_url('/mod/lesson/importppt.php',array('id'=>$this->page->cm->id, 'pageid'=>$prevpageid));
- $links[] = html_writer::link($importppturl, get_string('importppt', 'lesson'));
-
$manager = lesson_page_type_manager::get($lesson);
foreach ($manager->get_add_page_type_links($prevpageid) as $link) {
$link['addurl']->param('firstpage', 1);
defined('MOODLE_INTERNAL') || die();
-$module->version = 2012061700; // The current module version (Date: YYYYMMDDXX)
+$module->version = 2012061701; // The current module version (Date: YYYYMMDDXX)
$module->requires = 2012061700; // Requires this Moodle version
$module->component = 'mod_lesson'; // Full name of the plugin (used for diagnostics)
$module->cron = 0;
#page-mod-quiz-view .generalbox#feedback {width:70%;margin-left:auto;margin-right:auto;padding-bottom:15px;}
#page-mod-quiz-view .generalbox#feedback h2 {margin: 0;}
#page-mod-quiz-view .generalbox#feedback h3 {text-align: left;}
+#page-mod-quiz-view.dir-rtl .generalbox#feedback h3 {text-align: center;}
#page-mod-quiz-view .generalbox#feedback .overriddennotice {text-align: center;font-size: 0.7em;}
.quizstartbuttondiv.quizsecuremoderequired input { display: none; }
.jsenabled .quizstartbuttondiv.quizsecuremoderequired input { display: inline; }
#page-mod-quiz-edit div.question div.content .singlequestion .questiontext{display:inline-block;}
#page-mod-quiz-edit div.question div.content .singlequestion .questionpreview{background-color:#eee;}
#page-mod-quiz-edit div.question div.content .questiontype{display:block;clear:left;float:left;}
+#page-mod-quiz-edit.dir-rtl div.question div.content .questiontype {clear: right;float: right;}
#page-mod-quiz-edit div.question div.content .questionpreview {display:block;float:left;margin-left:0.3em;padding-left:0.2em;padding-right:0.2em;}
#page-mod-quiz-edit div.question div.content .questionpreview a{background-color:#eee;}
#page-mod-quiz-edit div.question div.content div.quiz_randomquestion .questionpreview{display:inline;float:none;}
#page-mod-quiz-edit.dir-rtl .quizpagedelete {left: 0.2em;right:auto;}
#page-mod-quiz-edit.dir-rtl div.quizcontents {clear: right;float: right;}
#page-mod-quiz-edit.dir-rtl .questionbankwindow.block {float: left;}
-#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
\ No newline at end of file
+#page-question-edit.dir-rtl td.creatorname, #page-question-edit.dir-rtl td.modifiername {text-align: center;}
+.path-question.dir-rtl input[name="maxmark"],
+.path-question-type.dir-rtl input[name="defaultmark"],
+#page-mod-quiz-edit.dir-rtl div.points input {direction: ltr;text-align: left;}
* @param array $grades grades array of users with grades - used when $userid = 0
*/
function scorm_set_completion($scorm, $userid, $completionstate = COMPLETION_COMPLETE, $grades = array()) {
- if (!completion_info::is_enabled()) {
- return;
- }
-
$course = new stdClass();
$course->id = $scorm->course;
+ $completion = new completion_info($course);
+
+ // Check if completion is enabled site-wide, or for the course
+ if (!$completion->is_enabled()) {
+ return;
+ }
$cm = get_coursemodule_from_instance('scorm', $scorm->id, $scorm->course);
- if (!empty($cm)) {
- $completion = new completion_info($course);
- if (empty($userid)) { //we need to get all the relevant users from $grades param.
- foreach ($grades as $grade) {
- $completion->update_state($cm, $completionstate, $grade->userid);
- }
- } else {
- $completion->update_state($cm, $completionstate, $userid);
+ if (empty($cm) || !$completion->is_enabled($cm)) {
+ return;
+ }
+
+ if (empty($userid)) { //we need to get all the relevant users from $grades param.
+ foreach ($grades as $grade) {
+ $completion->update_state($cm, $completionstate, $grade->userid);
}
+ } else {
+ $completion->update_state($cm, $completionstate, $userid);
}
}
xxx_dndupload_register() and xxx_dndupload_handle($uploadinfo) see:
http://docs.moodle.org/dev/Implementing_Course_drag_and_drop_upload_support_in_a_module
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables: $selectdata and $params.
+
+
=== 2.2 ===
required changes in code:
* textlib->asort() replaced by specialized collatorlib::asort()
* use new make_temp_directory() and make_cache_directory()
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables: $selectdata and $params.
+
=== 2.1 ===
required changes in code:
* add new support for basic restore from 1.9
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables: $selectdata and $params.
+
=== 2.0 ===
$string['backpage'] = 'Back to page';
$string['backtomapmenu'] = 'Back to map menu';
$string['changerate'] = 'Do you wish to change it?';
+$string['cannoteditpage'] = 'You can not edit this page.';
$string['cannotmanagefiles'] = 'You don\'t have permission to manage the wiki files.';
$string['cannotviewfiles'] = 'You don\'t have permission to view the wiki files.';
+$string['cannotviewpage'] = 'You can not view this page.';
$string['comparesel'] = 'Compare selected';
$string['comments'] = 'Comments';
$string['commentscount'] = 'Comments ({$a})';