#page-admin-tool-customlang-index .continuebutton {
margin-top: 1em;
}
+
+.path-admin-tool-customlang #translator .standard.master.cell.c2 {
+ word-break: break-all;
+}
//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]);
}
}
$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 .
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();
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));
}
/**
- * 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;
}
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 {
$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);
}
// 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']);
}
//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'];
$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)) {
* @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;
}
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
*
$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);
}
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++;
}
}
$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();
- }
- }
}
$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);
}
}
+ /**
+ * 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
* @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
//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';
* @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
*
* @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
*
* @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;
return true;
}
+
/**
- * Returns list of children.
+ * Returns list of children nodes
+ *
* @return array of file_info instances
*/
public function get_children() {
+ return $this->get_filtered_children('*', false, true);
+ }
+
+ /**
+ * Helper 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_workshop',
+ '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' => 'mod_workshop', 'filearea' => $this->filearea),
- 'itemid', "DISTINCT itemid");
- foreach ($itemids as $itemid => $unused) {
- if ($child = $this->browser->get_file_info($this->context, 'mod_workshop', $this->filearea, $itemid)) {
+ foreach ($rs as $record) {
+ if (($child = $this->browser->get_file_info($this->context, 'mod_workshop', $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.
+ *
+ * NOTE: We don't need the exact number of non empty children if it is >=2
+ * In this function 1 is never returned to avoid skipping the single subfolder
+ *
+ * @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
* this.viewmode, store current view mode
* this.pathbar, reference to the Node with path bar
* this.pathnode, a Node element representing one folder in a path bar (not attached anywhere, just used for template)
+ * this.currentpath, the current path in the repository (or last requested path)
*
* Filepicker options:
* =====
* this.filelist, cached filelist
* this.pages
* this.page
- * this.filepath, current path
+ * this.filepath, current path (each element of the array is a part of the breadcrumb)
* this.logindata, cached login form
*/
// save current path and filelist (in case we want to jump to other viewmode)
this.filepath = e.node.origpath;
this.filelist = e.node.origlist;
+ this.currentpath = e.node.path;
this.print_path();
this.content_scrolled();
}
if (this.active_repo.dynload) {
this.list({'path':node.path});
} else {
- this.filepath = node.path;
this.filelist = node.children;
this.view_files();
}
if (this.active_repo.dynload) {
this.list({'path':node.path});
} else {
- this.filepath = node.path;
this.filelist = node.children;
this.view_files();
}
}
this.active_repo.nextpagerequested = true;
var nextpage = this.active_repo.page+1;
- var args = {page:nextpage, repo_id:this.active_repo.id, path:this.active_repo.path};
+ var args = {
+ page: nextpage,
+ repo_id: this.active_repo.id,
+ };
var action = this.active_repo.issearchresult ? 'search' : 'list';
this.request({
+ path: this.currentpath,
scope: this,
action: action,
client_id: this.options.client_id,
params: args,
callback: function(id, obj, args) {
var scope = args.scope;
- // check that we are still in the same repository and are expecting this page
+ // Check that we are still in the same repository and are expecting this page. We have no way
+ // to compare the requested page and the one returned, so we assume that if the last chunk
+ // of the breadcrumb is similar, then we probably are on the same page.
+ var samepage = true;
+ if (obj.path && scope.filepath) {
+ var pathbefore = scope.filepath[scope.filepath.length-1];
+ var pathafter = obj.path[obj.path.length-1];
+ if (pathbefore.path != pathafter.path) {
+ samepage = false;
+ }
+ }
if (scope.active_repo.hasmorepages && obj.list && obj.page &&
obj.repo_id == scope.active_repo.id &&
- obj.page == scope.active_repo.page+1 && obj.path == scope.path) {
+ obj.page == scope.active_repo.page+1 && samepage) {
scope.parse_repository_options(obj, true);
scope.view_files(obj.list)
}
if (!args.repo_id) {
args.repo_id = this.active_repo.id;
}
+ if (!args.path) {
+ args.path = '';
+ }
+ this.currentpath = args.path;
this.request({
action: 'list',
client_id: this.options.client_id,
toolbar.one('.fp-tb-refresh').one('a,button').on('click', function(e) {
e.preventDefault();
if (!this.active_repo.norefresh) {
- this.list();
+ this.list({ path: this.currentpath });
}
}, this);
toolbar.one('.fp-tb-search form').
public function get_listing($path = '', $page = '') {
}
+
/**
- * Prepares list of files before passing it to AJAX, makes sure data is in the correct
- * format and stores formatted values.
+ * Prepare the breadcrumb.
*
- * @param array|stdClass $listing result of get_listing() or search() or file_get_drafarea_files()
- * @return array
+ * @param array $breadcrumb contains each element of the breadcrumb.
+ * @return array of breadcrumb elements.
+ * @since 2.3.3
*/
- public static function prepare_listing($listing) {
+ protected static function prepare_breadcrumb($breadcrumb) {
global $OUTPUT;
-
- $defaultfoldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
- // prepare $listing['path'] or $listing->path
- if (is_array($listing) && isset($listing['path']) && is_array($listing['path'])) {
- $path = &$listing['path'];
- } else if (is_object($listing) && isset($listing->path) && is_array($listing->path)) {
- $path = &$listing->path;
- }
- if (isset($path)) {
- $len = count($path);
- for ($i=0; $i<$len; $i++) {
- if (is_array($path[$i]) && !isset($path[$i]['icon'])) {
- $path[$i]['icon'] = $defaultfoldericon;
- } else if (is_object($path[$i]) && !isset($path[$i]->icon)) {
- $path[$i]->icon = $defaultfoldericon;
- }
+ $foldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
+ $len = count($breadcrumb);
+ for ($i = 0; $i < $len; $i++) {
+ if (is_array($breadcrumb[$i]) && !isset($breadcrumb[$i]['icon'])) {
+ $breadcrumb[$i]['icon'] = $foldericon;
+ } else if (is_object($breadcrumb[$i]) && !isset($breadcrumb[$i]->icon)) {
+ $breadcrumb[$i]->icon = $foldericon;
}
}
+ return $breadcrumb;
+ }
- // prepare $listing['list'] or $listing->list
- if (is_array($listing) && isset($listing['list']) && is_array($listing['list'])) {
- $listing['list'] = array_values($listing['list']); // convert to array
- $files = &$listing['list'];
- } else if (is_object($listing) && isset($listing->list) && is_array($listing->list)) {
- $listing->list = array_values($listing->list); // convert to array
- $files = &$listing->list;
- } else {
- return $listing;
- }
- $len = count($files);
- for ($i=0; $i<$len; $i++) {
- if (is_object($files[$i])) {
- $file = (array)$files[$i];
+ /**
+ * Prepare the file/folder listing.
+ *
+ * @param array $list of files and folders.
+ * @return array of files and folders.
+ * @since 2.3.3
+ */
+ protected static function prepare_list($list) {
+ global $OUTPUT;
+ $foldericon = $OUTPUT->pix_url(file_folder_icon(24))->out(false);
+
+ // Reset the array keys because non-numeric keys will create an object when converted to JSON.
+ $list = array_values($list);
+
+ $len = count($list);
+ for ($i = 0; $i < $len; $i++) {
+ if (is_object($list[$i])) {
+ $file = (array)$list[$i];
$converttoobject = true;
} else {
- $file = & $files[$i];
+ $file =& $list[$i];
$converttoobject = false;
}
if (isset($file['size'])) {
$file['size'] = (int)$file['size'];
$file['size_f'] = display_size($file['size']);
}
- if (isset($file['license']) &&
- get_string_manager()->string_exists($file['license'], 'license')) {
+ if (isset($file['license']) && get_string_manager()->string_exists($file['license'], 'license')) {
$file['license_f'] = get_string($file['license'], 'license');
}
if (isset($file['image_width']) && isset($file['image_height'])) {
}
if (!isset($file['icon'])) {
if ($isfolder) {
- $file['icon'] = $defaultfoldericon;
+ $file['icon'] = $foldericon;
} else if ($filename) {
$file['icon'] = $OUTPUT->pix_url(file_extension_icon($filename, 24))->out(false);
}
}
+
+ // Recursively loop over children.
+ if (isset($file['children'])) {
+ $file['children'] = self::prepare_list($file['children']);
+ }
+
+ // Convert the array back to an object.
if ($converttoobject) {
- $files[$i] = (object)$file;
+ $list[$i] = (object)$file;
}
}
+ return $list;
+ }
+
+ /**
+ * Prepares list of files before passing it to AJAX, makes sure data is in the correct
+ * format and stores formatted values.
+ *
+ * @param array|stdClass $listing result of get_listing() or search() or file_get_drafarea_files()
+ * @return array
+ */
+ public static function prepare_listing($listing) {
+ $wasobject = false;
+ if (is_object($listing)) {
+ $listing = (array) $listing;
+ $wasobject = true;
+ }
+
+ // Prepare the breadcrumb, passed as 'path'.
+ if (isset($listing['path']) && is_array($listing['path'])) {
+ $listing['path'] = self::prepare_breadcrumb($listing['path']);
+ }
+
+ // Prepare the listing of objects.
+ if (isset($listing['list']) && is_array($listing['list'])) {
+ $listing['list'] = self::prepare_list($listing['list']);
+ }
+
+ // Convert back to an object.
+ if ($wasobject) {
+ $listing = (object) $listing;
+ }
return $listing;
}
*
* @since 2.0
* @package repository_local
+ * @copyright 2012 Marina Glancy
* @copyright 2009 Dongsheng Cai {@link http://dongsheng.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class repository_local extends repository {
- /**
- * local plugin doesn't require login, so list all files
- * @return mixed
- */
- public function print_login() {
- return $this->get_listing();
- }
-
/**
* Get file listing
*
* @param string $encodedpath
+ * @param string $page no paging is used in repository_local
* @return mixed
*/
public function get_listing($encodedpath = '', $page = '') {
$ret['dynload'] = true;
$ret['nosearch'] = true;
$ret['nologin'] = true;
- $list = array();
+ $ret['list'] = array();
+
+ $itemid = null;
+ $filename = null;
+ $filearea = null;
+ $filepath = null;
+ $component = null;
if (!empty($encodedpath)) {
$params = unserialize(base64_decode($encodedpath));
- if (is_array($params)) {
+ if (is_array($params) && isset($params['contextid'])) {
$component = is_null($params['component']) ? NULL : clean_param($params['component'], PARAM_COMPONENT);
$filearea = is_null($params['filearea']) ? NULL : clean_param($params['filearea'], PARAM_AREA);
$itemid = is_null($params['itemid']) ? NULL : clean_param($params['itemid'], PARAM_INT);
$filename = is_null($params['filename']) ? NULL : clean_param($params['filename'], PARAM_FILE);
$context = get_context_instance_by_id(clean_param($params['contextid'], PARAM_INT));
}
+ }
+ if (empty($context) && !empty($this->context)) {
+ $context = $this->context->get_course_context(false);
+ }
+ if (empty($context)) {
+ $context = context_system::instance();
+ }
+
+ // prepare list of allowed extensions: $extensions is either string '*'
+ // or array of lowercase extensions, i.e. array('.gif','.jpg')
+ $extensions = optional_param_array('accepted_types', '', PARAM_RAW);
+ if (empty($extensions) || $extensions === '*' || (is_array($extensions) && in_array('*', $extensions))) {
+ $extensions = '*';
} else {
- $itemid = null;
- $filename = null;
- $filearea = null;
- $filepath = null;
- $component = null;
- if (!empty($this->context)) {
- list($context, $course, $cm) = get_context_info_array($this->context->id);
- if (is_object($course)) {
- $context = get_context_instance(CONTEXT_COURSE, $course->id);
- } else {
- $context = get_system_context();
- }
- } else {
- $context = get_system_context();
+ if (!is_array($extensions)) {
+ $extensions = array($extensions);
}
+ $extensions = array_map('textlib::strtolower', $extensions);
}
+ // build file tree
$browser = get_file_browser();
-
- $list = array();
- if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
- // build file tree
- $element = repository_local_file::retrieve_file_info($fileinfo, $this);
- $nonemptychildren = $element->get_non_empty_children();
- foreach ($nonemptychildren as $child) {
- $list[] = (array)$child->get_node();
- }
- } else {
+ if (!($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename))) {
// if file doesn't exist, build path nodes root of current context
$fileinfo = $browser->get_file_info($context, null, null, null, null, null);
}
+ $ret['list'] = $this->get_non_empty_children($fileinfo, $extensions);
+
// build path navigation
+ $path = array();
+ for ($level = $fileinfo; $level; $level = $level->get_parent()) {
+ array_unshift($path, $level);
+ }
+ array_unshift($path, null);
$ret['path'] = array();
- $element = repository_local_file::retrieve_file_info($fileinfo, $this);
- for ($level = $element; $level; $level = $level->get_parent()) {
- if ($level == $element || !$level->can_skip()) {
- array_unshift($ret['path'], $level->get_node_path());
+ for ($i=1; $i<count($path); $i++) {
+ if ($path[$i] == $fileinfo || !$this->can_skip($path[$i], $extensions, $path[$i-1])) {
+ $ret['path'][] = $this->get_node_path($path[$i]);
}
}
- $ret['list'] = array_filter($list, array($this, 'filter'));
return $ret;
}
/**
- * Local file don't support to link to external links
+ * Tells how the file can be picked from this repository
*
* @return int
*/
// this should be realtime
return 0;
}
-}
-
-/**
- * Class to cache some information about file
- *
- * This class is a wrapper to instances of file_info. It caches such information as
- * parent and list of children. It also stores an array of already retrieved elements.
- *
- * It also implements more comprehensive algorithm for checking if folder is empty
- * (taking into account the filtering of the files). To decrease number of levels
- * we check if some subfolders can be skipped from the tree.
- *
- * As a result we display in Server files repository only non-empty folders and skip
- * filearea folders if this is the only filearea in the module.
- * For non-admin the course categories are not shown as well (courses are shown as a list)
- *
- * @package repository_local
- * @copyright 2012 Marina Glancy
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class repository_local_file {
- /** @var array stores already retrieved files */
- private static $cachedfiles = array();
- /** @var file_info Stores the original file */
- public $fileinfo;
- /** @var bool whether this file is directory */
- private $isdir;
- /** @var array caches retrieved children */
- private $children = null;
- /** @var array caches retrieved information whether this file is an empty directory */
- protected $isempty = null;
- /** @var repository link to the container repository (for filtering the results) */
- private $repository;
- /** @var repository_local_file link to parent directory */
- protected $parent;
- /** @var bool caches calculated information on whether this directory must be skipped in the tree */
- private $skip = null;
/**
- * Creates (or retrieves from cache) the repository_local_file object for $file_info
+ * Returns all children elements that have one of the specified extensions
+ *
+ * This function may skip subfolders and recursively add their children
+ * {@link repository_local::can_skip()}
*
* @param file_info $fileinfo
- * @param repository $repository
- * @param repository_local_file $parent
- * @return repository_local_file
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @return array array of file_info elements
*/
- public static function retrieve_file_info(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
- $encodedpath = base64_encode(serialize($fileinfo->get_params()));
- if (!isset(self::$cachedfiles[$encodedpath])) {
- self::$cachedfiles[$encodedpath] = new repository_local_file($fileinfo, $repository, $parent);
+ private function get_non_empty_children(file_info $fileinfo, $extensions) {
+ $nonemptychildren = $fileinfo->get_non_empty_children($extensions);
+ $list = array();
+ foreach ($nonemptychildren as $child) {
+ if ($this->can_skip($child, $extensions, $fileinfo)) {
+ $list = array_merge($list, $this->get_non_empty_children($child, $extensions));
+ } else {
+ $list[] = $this->get_node($child);
+ }
}
- return self::$cachedfiles[$encodedpath];
+ return $list;
}
/**
- * Creates an object
+ * Whether this folder may be skipped in folder hierarchy
+ *
+ * 1. Skip the name of a single filearea in a module
+ * 2. Skip course categories for non-admins who do not have navshowmycoursecategories setting
*
* @param file_info $fileinfo
- * @param repository $repository
- * @param repository_local_file $parent
+ * @param string|array $extensions, for example '*' or array('.gif','.jpg')
+ * @param file_info|int $parent specify parent here if we know it to avoid creating extra objects
+ * @return bool
*/
- private function __construct(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
- $this->repository = $repository;
- $this->fileinfo = $fileinfo;
- $this->isdir = $fileinfo->is_directory();
- if (!$this->isdir) {
- $node = array('title' => $this->fileinfo->get_visible_name());
- $this->isempty = !$repository->filter($node);
- $this->skip = false;
+ private function can_skip(file_info $fileinfo, $extensions, $parent = -1) {
+ global $CFG;
+ if (!$fileinfo->is_directory()) {
+ // do not skip files
+ return false;
}
+ if ($fileinfo instanceof file_info_context_coursecat) {
+ // This is a course category. For non-admins we do not display categories
+ return empty($CFG->navshowmycoursecategories) &&
+ !has_capability('moodle/course:update', context_system::instance());
+ } else if ($fileinfo instanceof file_info_context_course ||
+ $fileinfo instanceof file_info_context_user ||
+ $fileinfo instanceof file_info_area_course_legacy ||
+ $fileinfo instanceof file_info_context_module ||
+ $fileinfo instanceof file_info_context_system) {
+ // these instances can never be filearea inside an activity, they will never be skipped
+ return false;
+ } else {
+ $params = $fileinfo->get_params();
+ if (strlen($params['filearea']) &&
+ ($params['filepath'] === '/' || empty($params['filepath'])) &&
+ ($params['filename'] === '.' || empty($params['filename'])) &&
+ context::instance_by_id($params['contextid'])->contextlevel == CONTEXT_MODULE) {
+ if ($parent === -1) {
+ $parent = $fileinfo->get_parent();
+ }
+ // This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
+ if ($parent && ($parent instanceof file_info_context_module)) {
+ if ($parent->count_non_empty_children($extensions, 2) <= 1) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
}
/**
- * Returns node for $ret['list']
+ * Converts file_info object to element of repository return list
*
+ * @param file_info $fileinfo
* @return array
*/
- public function get_node() {
+ private function get_node(file_info $fileinfo) {
global $OUTPUT;
- $encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
+ $encodedpath = base64_encode(serialize($fileinfo->get_params()));
$node = array(
- 'title' => $this->fileinfo->get_visible_name(),
- 'datemodified' => $this->fileinfo->get_timemodified(),
- 'datecreated' => $this->fileinfo->get_timecreated()
+ 'title' => $fileinfo->get_visible_name(),
+ 'datemodified' => $fileinfo->get_timemodified(),
+ 'datecreated' => $fileinfo->get_timecreated()
);
- if ($this->isdir) {
+ if ($fileinfo->is_directory()) {
$node['path'] = $encodedpath;
$node['thumbnail'] = $OUTPUT->pix_url(file_folder_icon(90))->out(false);
$node['children'] = array();
} else {
- $node['size'] = $this->fileinfo->get_filesize();
- $node['author'] = $this->fileinfo->get_author();
- $node['license'] = $this->fileinfo->get_license();
- $node['isref'] = $this->fileinfo->is_external_file();
- if ($this->fileinfo->get_status() == 666) {
+ $node['size'] = $fileinfo->get_filesize();
+ $node['author'] = $fileinfo->get_author();
+ $node['license'] = $fileinfo->get_license();
+ $node['isref'] = $fileinfo->is_external_file();
+ if ($fileinfo->get_status() == 666) {
$node['originalmissing'] = true;
}
$node['source'] = $encodedpath;
- $node['thumbnail'] = $OUTPUT->pix_url(file_file_icon($this->fileinfo, 90))->out(false);
- $node['icon'] = $OUTPUT->pix_url(file_file_icon($this->fileinfo, 24))->out(false);
- if ($imageinfo = $this->fileinfo->get_imageinfo()) {
+ $node['thumbnail'] = $OUTPUT->pix_url(file_file_icon($fileinfo, 90))->out(false);
+ $node['icon'] = $OUTPUT->pix_url(file_file_icon($fileinfo, 24))->out(false);
+ if ($imageinfo = $fileinfo->get_imageinfo()) {
// what a beautiful picture, isn't it
- $fileurl = new moodle_url($this->fileinfo->get_url());
- $node['realthumbnail'] = $fileurl->out(false, array('preview' => 'thumb', 'oid' => $this->fileinfo->get_timemodified()));
- $node['realicon'] = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $this->fileinfo->get_timemodified()));
+ $fileurl = new moodle_url($fileinfo->get_url());
+ $node['realthumbnail'] = $fileurl->out(false, array('preview' => 'thumb', 'oid' => $fileinfo->get_timemodified()));
+ $node['realicon'] = $fileurl->out(false, array('preview' => 'tinyicon', 'oid' => $fileinfo->get_timemodified()));
$node['image_width'] = $imageinfo['width'];
$node['image_height'] = $imageinfo['height'];
}
}
/**
- * Returns node for $ret['path']
+ * Converts file_info object to element of repository return path
*
+ * @param file_info $fileinfo
* @return array
*/
- public function get_node_path() {
- $encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
+ private function get_node_path(file_info $fileinfo) {
+ $encodedpath = base64_encode(serialize($fileinfo->get_params()));
return array(
'path' => $encodedpath,
- 'name' => $this->fileinfo->get_visible_name()
+ 'name' => $fileinfo->get_visible_name()
);
}
-
- /**
- * Checks if this is a directory
- *
- * @return bool
- */
- public function is_dir() {
- return $this->isdir;
- }
-
- /**
- * Returns children of this element
- *
- * @return array
- */
- public function get_children() {
- if (!$this->isdir) {
- return array();
- }
- if ($this->children === null) {
- $this->children = array();
- $children = $this->fileinfo->get_children();
- for ($i=0; $i<count($children); $i++) {
- $this->children[] = self::retrieve_file_info($children[$i], $this->repository, $this);
- }
- }
- return $this->children;
- }
-
- /**
- * Checks if this folder is empty (contains no non-empty children)
- *
- * @return bool
- */
- public function is_empty() {
- if ($this->isempty === null) {
- $this->isempty = true;
- if (!$this->fileinfo->is_empty_area()) {
- // even if is_empty_area() returns false, element still may be empty
- $children = $this->get_children();
- if (!empty($children)) {
- // 1. Let's look at already retrieved children
- foreach ($children as $childnode) {
- if ($childnode->isempty === false) {
- // we already calculated isempty for a child, and it is not empty
- $this->isempty = false;
- break;
- }
- }
- if ($this->isempty) {
- // 2. now we know that this directory contains children that are either empty or we don't know
- foreach ($children as $childnode) {
- if (!$childnode->is_empty()) {
- $this->isempty = false;
- break;
- }
- }
- }
- }
- }
- }
- return $this->isempty;
- }
-
- /**
- * Returns the parent element
- *
- * @return repository_local_file
- */
- public function get_parent() {
- if ($this->parent === null) {
- if ($parent = $this->fileinfo->get_parent()) {
- $this->parent = self::retrieve_file_info($parent, $this->repository);
- } else {
- $this->parent = false;
- }
- }
- return $this->parent;
- }
-
- /**
- * Wether this folder may be skipped in tree view
- *
- * @return bool
- */
- public function can_skip() {
- global $CFG;
- if ($this->skip === null) {
- $this->skip = false;
- if ($this->fileinfo instanceof file_info_stored) {
- $params = $this->fileinfo->get_params();
- if (strlen($params['filearea']) && $params['filepath'] == '/' && $params['filename'] == '.') {
- // This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
- if ($parent = $this->get_parent()) {
- $siblings = $parent->get_children();
- $countnonempty = 0;
- foreach ($siblings as $sibling) {
- if (!$sibling->is_empty()) {
- $countnonempty++;
- if ($countnonempty > 1) {
- break;
- }
- }
- }
- if ($countnonempty <= 1) {
- $this->skip = true;
- }
- }
- }
- } else if ($this->fileinfo instanceof file_info_context_coursecat) {
- // This is a course category. For non-admins we do not display categories
- $this->skip = empty($CFG->navshowmycoursecategories) &&
- !has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM));
- }
- }
- return $this->skip;
- }
-
- /**
- * Returns array of children who have any elmenets
- *
- * If a subfolder can be skipped - list children of subfolder instead
- * (recursive function)
- *
- * @return array
- */
- public function get_non_empty_children() {
- $children = $this->get_children();
- $nonemptychildren = array();
- foreach ($children as $child) {
- if (!$child->is_empty()) {
- if ($child->can_skip()) {
- $nonemptychildren = array_merge($nonemptychildren, $child->get_non_empty_children());
- } else {
- $nonemptychildren[] = $child;
- }
- }
- }
- return $nonemptychildren;
- }
}
<?php
-$hasheading = ($PAGE->heading);
-$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
-$hasfooter = (empty($PAGE->layout_options['nofooter']));
$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
$hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$showsidepre = $hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT);
+$showsidepost = $hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT);
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
$bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre && !$showsidepost) {
$bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
+} else if ($showsidepost && !$showsidepre) {
$bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else if (!$showsidepost && !$showsidepre) {
$bodyclasses[] = 'content-only';
}
+if ($hascustommenu) {
+ $bodyclasses[] = 'has_custom_menu';
+}
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
<!-- START OF HEADER -->
- <div id="wrapper" class="clearfix">
-
- <div id="page-header">
- <div id="page-header-wrapper" class="clearfix">
- <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
- <div class="headermenu">
- <?php
- echo $OUTPUT->login_info();
- echo $OUTPUT->lang_menu();
- echo $PAGE->headingmenu;
- ?>
- </div>
- </div>
- </div>
+ <div id="wrapper" class="clearfix">
+
+ <div id="page-header">
+ <div id="page-header-wrapper" class="clearfix">
+ <h1 class="headermain"><?php echo $PAGE->heading ?></h1>
+ <div class="headermenu">
+ <?php
+ echo $OUTPUT->login_info();
+ echo $OUTPUT->lang_menu();
+ echo $PAGE->headingmenu;
+ ?>
+ </div>
+ </div>
+ </div>
+
+ <?php if ($hascustommenu) { ?>
+ <div id="custommenu"><?php echo $custommenu; ?></div>
+ <?php } ?>
<div class="clearer"></div> <!-- temporarily added on 06/25/10 -->
<!-- START OF CONTENT -->
- <div id="page-content-wrapper" class="clearfix">
- <div id="page-content">
- <div id="region-main-box">
- <div id="region-post-box">
-
- <div id="region-main-wrap">
- <div id="region-main">
- <div class="region-content">
- <?php echo $OUTPUT->main_content() ?>
- </div>
- </div>
- </div>
-
- <?php if ($hassidepre) { ?>
- <div id="region-pre">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
- </div>
- </div>
- <?php } ?>
-
- <?php if ($hassidepost) { ?>
- <div id="region-post">
- <div class="region-content">
- <?php echo $OUTPUT->blocks_for_region('side-post') ?>
- </div>
- </div>
- <?php } ?>
-
- </div>
- </div>
- </div>
- </div>
+ <div id="page-content-wrapper" class="clearfix">
+ <div id="page-content">
+ <div id="region-main-box">
+ <div id="region-post-box">
+
+ <div id="region-main-wrap">
+ <div id="region-main">
+ <div class="region-content">
+ <?php echo $OUTPUT->main_content() ?>
+ </div>
+ </div>
+ </div>
+
+ <?php if ($hassidepre) { ?>
+ <div id="region-pre" class="block-region">
+ <div class="region-content">
+ <?php echo $OUTPUT->blocks_for_region('side-pre') ?>
+ </div>
+ </div>
+ <?php } ?>
+
+ <?php if ($hassidepost) { ?>
+ <div id="region-post" class="block-region">
+ <div class="region-content">
+ <?php echo $OUTPUT->blocks_for_region('side-post') ?>
+ </div>
+ </div>
+ <?php } ?>
+
+ </div>
+ </div>
+ </div>
+ </div>
<!-- END OF CONTENT -->
<!-- START OF FOOTER -->
- <div id="page-footer">
- <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
+ <div id="page-footer">
+ <p class="helplink"><?php echo page_doc_link(get_string('moodledocslink')) ?></p>
- <?php
- echo $OUTPUT->login_info();
- echo $OUTPUT->home_link();
- echo $OUTPUT->standard_footer_html();
- ?>
- </div>
+ <?php
+ echo $OUTPUT->login_info();
+ echo $OUTPUT->home_link();
+ echo $OUTPUT->standard_footer_html();
+ ?>
+ </div>
<!-- END OF FOOTER -->
- </div> <!-- END #wrapper -->
+ </div> <!-- END #wrapper -->
</div><!-- END #page -->
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</body>
-</html>
\ No newline at end of file
+</html>
$hasheading = ($PAGE->heading);
$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
$hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
+$hassidepost = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-post', $OUTPUT));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+$showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side-post', $OUTPUT));
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
$bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre && !$showsidepost) {
$bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
+} else if ($showsidepost && !$showsidepre) {
$bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else if (!$showsidepost && !$showsidepre) {
$bodyclasses[] = 'content-only';
}
+if ($hascustommenu) {
+ $bodyclasses[] = 'has_custom_menu';
+}
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
</div>
</div>
+ <?php if ($hascustommenu) { ?>
+ <div id="custommenu"><?php echo $custommenu; ?></div>
+ <?php } ?>
+
<?php if ($hasnavbar) { ?>
<div class="navbar clearfix">
<div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
</div>
<?php if ($hassidepre) { ?>
- <div id="region-pre">
+ <div id="region-pre" class="block-region">
<div class="region-content">
<?php echo $OUTPUT->blocks_for_region('side-pre') ?>
</div>
<?php } ?>
<?php if ($hassidepost) { ?>
- <div id="region-post">
+ <div id="region-post" class="block-region">
<div class="region-content">
<?php echo $OUTPUT->blocks_for_region('side-post') ?>
</div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</body>
-</html>
\ No newline at end of file
+</html>
$hasheading = ($PAGE->heading);
$hasnavbar = (empty($PAGE->layout_options['nonavbar']) && $PAGE->has_navbar());
$hasfooter = (empty($PAGE->layout_options['nofooter']));
-$hassidepre = $PAGE->blocks->region_has_content('side-pre', $OUTPUT);
-$hassidepost = $PAGE->blocks->region_has_content('side-post', $OUTPUT);
+$hassidepre = (empty($PAGE->layout_options['noblocks']) && $PAGE->blocks->region_has_content('side-pre', $OUTPUT));
+$haslogininfo = (empty($PAGE->layout_options['nologininfo']));
+
+$showsidepre = ($hassidepre && !$PAGE->blocks->region_completely_docked('side-pre', $OUTPUT));
+
+$custommenu = $OUTPUT->custom_menu();
+$hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu));
$bodyclasses = array();
-if ($hassidepre && !$hassidepost) {
+if ($showsidepre ) {
$bodyclasses[] = 'side-pre-only';
-} else if ($hassidepost && !$hassidepre) {
- $bodyclasses[] = 'side-post-only';
-} else if (!$hassidepost && !$hassidepre) {
+} else {
$bodyclasses[] = 'content-only';
}
+if ($hascustommenu) {
+ $bodyclasses[] = 'has_custom_menu';
+}
echo $OUTPUT->doctype() ?>
<html <?php echo $OUTPUT->htmlattributes() ?>>
</div>
</div>
+ <?php if ($hascustommenu) { ?>
+ <div id="custommenu"><?php echo $custommenu; ?></div>
+ <?php } ?>
+
<?php if ($hasnavbar) { ?>
<div class="navbar clearfix">
<div class="breadcrumb"><?php echo $OUTPUT->navbar(); ?></div>
<?php echo $OUTPUT->standard_end_of_body_html() ?>
</body>
-</html>
\ No newline at end of file
+</html>
defined('MOODLE_INTERNAL') || die();
-$version = 2012062502.06; // YYYYMMDD = weekly release date of this DEV branch
+$version = 2012062502.08; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes
//detect the missing capabilities
foreach ($servicecaps as $functioname => $functioncaps) {
foreach ($functioncaps as $functioncap) {
- if (!key_exists($functioncap, $usercaps)) {
+ if (!array_key_exists($functioncap, $usercaps)) {
if (!isset($usersmissingcaps[$user->id])
or array_search($functioncap, $usersmissingcaps[$user->id]) === false) {
$usersmissingcaps[$user->id][] = $functioncap;