print_error('phpvaroff', 'debug', '', (object)array('name'=>'session.auto_start', 'link'=>$documentationlink));
}
-if (ini_get_bool('magic_quotes_runtime')) {
- print_error('phpvaroff', 'debug', '', (object)array('name'=>'magic_quotes_runtime', 'link'=>$documentationlink));
-}
-
if (!ini_get_bool('file_uploads')) {
print_error('phpvaron', 'debug', '', (object)array('name'=>'file_uploads', 'link'=>$documentationlink));
}
'moodle/backup:backupcourse',
'moodle/category:manage',
'moodle/course:create',
- 'moodle/site:approvecourse'
+ 'moodle/site:approvecourse',
+ 'moodle/restore:restorecourse'
);
if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
// Speedup for non-admins, add all caps used on this page.
array('moodle/category:manage')
)
);
+ $ADMIN->add('courses',
+ new admin_externalpage('restorecourse', new lang_string('restorecourse', 'admin'),
+ new moodle_url('/backup/restorefile.php', array('contextid' => context_system::instance()->id)),
+ array('moodle/course:create')
+ )
+ );
// Course Default Settings Page.
// NOTE: these settings must be applied after all other settings because they depend on them.
$temp->add(new admin_setting_configcheckbox('enabletgzbackups',
new lang_string('enabletgzbackups', 'admin'),
new lang_string('enabletgzbackups_desc', 'admin'), 0));
- $temp->add(new admin_setting_php_extension_enabled('zlibenabled',
- get_string('zlibenabled', 'admin'),
- get_string('enabletgzbackups_nozlib', 'admin'), 'zlib'));
$ADMIN->add('experimental', $temp);
}
}
-class problem_000006 extends problem_base {
- function title() {
- return 'PHP: magic_quotes_runtime is enabled';
- }
- function exists() {
- return (ini_get_bool('magic_quotes_runtime'));
- }
- function severity() {
- return SEVERITY_SIGNIFICANT;
- }
- function description() {
- return 'Your PHP configuration includes an enabled setting, magic_quotes_runtime, that <strong>must be disabled</strong> in order for Moodle to work correctly. Notable symptoms arising from this misconfiguration include strange display errors whenever a text field that includes single or double quotes is processed.';
- }
- function solution() {
- global $CFG;
- return '<p>There are two ways you can solve this problem:</p><ol><li>If you have access to your main <strong>php.ini</strong> file, then find the line that looks like this: <pre>magic_quotes_runtime = On</pre> and change it to <pre>magic_quotes_runtime = Off</pre> and then restart your web server. Be warned that this, as any other PHP setting change, might affect other web applications running on the server.</li><li>Finally, you may be able to change this setting just for your site by creating or editing the file <strong>'.$CFG->dirroot.'/.htaccess</strong> to contain this line: <pre>php_value magic_quotes_runtime "Off"</pre></li></ol>';
- }
-}
-
class problem_000007 extends problem_base {
function title() {
return 'PHP: file_uploads is disabled';
$qtypes = core_component::get_plugin_list('qtype');
foreach ($qtypes as $qtype => $notused) {
- $qtypes[$qtype] = get_string($qtype, 'qtype_' . $qtype);
+ $qtypes[$qtype] = get_string('pluginname', 'qtype_' . $qtype);
}
$mform->addElement('header', 'h1', 'Either extract a specific question_session');
if ($user->firstaccess == 0) {
$user->firstaccess = time();
}
- require_once($CFG->dirroot.'/user/lib.php');
user_update_user($user, false);
return AUTH_CONFIRM_OK;
}
/**
* Code the transformations to perform in the course in
* order to get transportable (encoded) links
+ * @param string $content content in which to encode links.
+ * @return string content with links encoded.
*/
static public function encode_content_links($content) {
- global $CFG;
-
- $base = preg_quote($CFG->wwwroot, '/');
// Link to the course main page (it also covers "&topic=xx" and "&week=xx"
- // because they don't become transformed (section number) in backup/restore
- $search = '/(' . $base . '\/course\/view.php\?id\=)([0-9]+)/';
- $content= preg_replace($search, '$@COURSEVIEWBYID*$2@$', $content);
+ // because they don't become transformed (section number) in backup/restore.
+ $content = self::encode_links_helper($content, 'COURSEVIEWBYID', '/course/view.php?id=');
+
+ // A few other key course links.
+ $content = self::encode_links_helper($content, 'GRADEINDEXBYID', '/grade/index.php?id=');
+ $content = self::encode_links_helper($content, 'GRADEREPORTINDEXBYID', '/grade/report/index.php?id=');
+ $content = self::encode_links_helper($content, 'BADGESVIEWBYID', '/badges/view.php?type=2&id=');
+ $content = self::encode_links_helper($content, 'USERINDEXVIEWBYID', '/user/index.php?id=');
return $content;
}
+ /**
+ * Helper method, used by encode_content_links.
+ * @param string $content content in which to encode links.
+ * @param unknown_type $name the name of this type of encoded link.
+ * @param unknown_type $path the path that identifies this type of link, up
+ * to the ?paramname= bit.
+ * @return string content with one type of link encoded.
+ */
+ static private function encode_links_helper($content, $name, $path) {
+ global $CFG;
+ $base = preg_quote($CFG->wwwroot . $path, '/');
+ return preg_replace('/(' . $base . ')([0-9]+)/', '$@' . $name . '*$2@$', $content);
+ }
+
// Protected API starts here
/**
static public function define_decode_rules() {
$rules = array();
- $rules[] = new restore_decode_rule('COURSEVIEWBYID', '/course/view.php?id=$1', 'course');
+ // Link to the course main page (it also covers "&topic=xx" and "&week=xx"
+ // because they don't become transformed (section number) in backup/restore.
+ $rules[] = new restore_decode_rule('COURSEVIEWBYID', '/course/view.php?id=$1', 'course');
- return $rules;
+ // A few other key course links.
+ $rules[] = new restore_decode_rule('GRADEINDEXBYID', '/grade/index.php?id=$1', 'course');
+ $rules[] = new restore_decode_rule('GRADEREPORTINDEXBYID', '/grade/report/index.php?id=$1', 'course');
+ $rules[] = new restore_decode_rule('BADGESVIEWBYID', '/badges/view.php?type=2&id=$1', 'course');
+ $rules[] = new restore_decode_rule('USERINDEXVIEWBYID', '/user/index.php?id=$1', 'course');
+ return $rules;
}
// Protected API starts here
require_login($course, null, $cm);
require_capability('moodle/restore:restorecourse', $context);
+if (is_null($course)) {
+ $coursefullname = $SITE->fullname;
+ $courseshortname = $SITE->shortname;
+} else {
+ $coursefullname = $course->fullname;
+ $courseshortname = $course->shortname;
+}
+
// Show page header.
-$PAGE->set_title($course->shortname . ': ' . get_string('restore'));
-$PAGE->set_heading($course->fullname);
+$PAGE->set_title($courseshortname . ': ' . get_string('restore'));
+$PAGE->set_heading($coursefullname);
$renderer = $PAGE->get_renderer('core','backup');
echo $OUTPUT->header();
require_login($course, false, $cm);
require_capability('moodle/restore:restorecourse', $context);
+if (is_null($course)) {
+ $courseid = 0;
+ $coursefullname = $SITE->fullname;
+} else {
+ $courseid = $course->id;
+ $coursefullname = $course->fullname;
+}
+
$browser = get_file_browser();
// check if tmp dir exists
'pathnamehash' => $file->get_pathnamehash(), 'contenthash' => $file->get_contenthash()));
} else {
// If it's some weird other kind of file then use old code.
- $filename = restore_controller::get_tempdir_name($course->id, $USER->id);
+ $filename = restore_controller::get_tempdir_name($courseid, $USER->id);
$pathname = $tmpdir . '/' . $filename;
$fileinfo->copy_to_pathname($pathname);
$restore_url = new moodle_url('/backup/restore.php', array(
$PAGE->set_url($url);
$PAGE->set_context($context);
-$PAGE->set_title(get_string('course') . ': ' . $course->fullname);
+$PAGE->set_title(get_string('course') . ': ' . $coursefullname);
$PAGE->set_heading($heading);
$PAGE->set_pagelayout('admin');
$form = new course_restore_form(null, array('contextid'=>$contextid));
$data = $form->get_data();
if ($data && has_capability('moodle/restore:uploadfile', $context)) {
- $filename = restore_controller::get_tempdir_name($course->id, $USER->id);
+ $filename = restore_controller::get_tempdir_name($courseid, $USER->id);
$pathname = $tmpdir . '/' . $filename;
$form->save_file('backupfile', $pathname);
$restore_url = new moodle_url('/backup/restore.php', array('contextid'=>$contextid, 'filename'=>$filename));
public static function decode_backup_temp_info($info) {
// We encode all data except null.
if ($info != null) {
- if (extension_loaded('zlib')) {
- return unserialize(gzuncompress(base64_decode($info)));
- } else {
- return unserialize(base64_decode($info));
- }
+ return unserialize(gzuncompress(base64_decode($info)));
}
return $info;
}
if ($info != null) {
// We compress if possible. It reduces db, network and memory storage. The saving is greater than CPU compression cost.
// Compression level 1 is chosen has it produces good compression with the smallest possible overhead, see MDL-40618.
- if (extension_loaded('zlib')) {
- return base64_encode(gzcompress(serialize($info), 1));
- } else {
- return base64_encode(serialize($info));
- }
+ return base64_encode(gzcompress(serialize($info), 1));
}
return $info;
}
--- /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/>.
+
+/**
+ * @package core_backup
+ * @category phpunit
+ * @copyright 2013 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
+require_once($CFG->dirroot . '/backup/moodle2/backup_course_task.class.php');
+
+
+
+/**
+ * Tests for encoding content links in backup_course_task.
+ *
+ * The code that this tests is acutally in backup/moodle2/backup_course_task.class.php,
+ * but there is no place for unit tests near there, and perhaps one day it will
+ * be refactored so it becomes more generic.
+ */
+class backup_course_task_testcase extends basic_testcase {
+
+ /**
+ * Test the encode_content_links method for course.
+ */
+ public function test_course_encode_content_links() {
+ global $CFG;
+ $encoded = backup_course_task::encode_content_links(
+ $CFG->wwwroot . '/course/view.php?id=123, ' .
+ $CFG->wwwroot . '/grade/index.php?id=123, ' .
+ $CFG->wwwroot . '/grade/report/index.php?id=123, ' .
+ $CFG->wwwroot . '/badges/view.php?type=2&id=123 and ' .
+ $CFG->wwwroot . '/user/index.php?id=123.');
+ $this->assertEquals('$@COURSEVIEWBYID*123@$, $@GRADEINDEXBYID*123@$, ' .
+ '$@GRADEREPORTINDEXBYID*123@$, $@BADGESVIEWBYID*123@$ and $@USERINDEXVIEWBYID*123@$.', $encoded);
+ }
+}
$badgeid = required_param('id', PARAM_INT);
$copy = optional_param('copy', 0, PARAM_BOOL);
-$delete = optional_param('delete', 0, PARAM_BOOL);
$activate = optional_param('activate', 0, PARAM_BOOL);
$deactivate = optional_param('lock', 0, PARAM_BOOL);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
}
$returnurl->remove_params('awards');
-if ($delete) {
- require_capability('moodle/badges:deletebadge', $context);
-
- $PAGE->url->param('delete', 1);
- if ($confirm) {
- require_sesskey();
- $badge->delete();
- redirect(new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid)));
- }
-
- $strheading = get_string('delbadge', 'badges');
- $PAGE->navbar->add($strheading);
- $PAGE->set_title($strheading);
- $PAGE->set_heading($badge->name);
- echo $OUTPUT->header();
- echo $OUTPUT->heading($strheading);
-
- $urlparams = array(
- 'id' => $badge->id,
- 'delete' => 1,
- 'confirm' => 1,
- 'sesskey' => sesskey()
- );
- $continue = new moodle_url('/badges/action.php', $urlparams);
- $cancel = new moodle_url('/badges/index.php', array('type' => $badge->type, 'id' => $badge->courseid));
-
- $message = get_string('delconfirm', 'badges', $badge->name);
- echo $OUTPUT->confirm($message, $continue, $cancel);
- echo $OUTPUT->footer();
- die;
-}
-
if ($copy) {
require_sesskey();
require_capability('moodle/badges:createbadge', $context);
$pageurl = new moodle_url('/badges/award.php', array('id' => $badgeid));
$issuerrole = new stdClass();
$issuerrole->roleid = $role;
- $roleselect = get_string('selectaward', 'badges') . $OUTPUT->single_select(new moodle_url($pageurl), 'role', $select, $role);
+ $roleselect = get_string('selectaward', 'badges') . $OUTPUT->single_select(new moodle_url($pageurl), 'role', $select, $role, null);
}
} else {
echo $OUTPUT->header();
$type = required_param('type', PARAM_INT);
$courseid = optional_param('id', 0, PARAM_INT);
$page = optional_param('page', 0, PARAM_INT);
-$activate = optional_param('activate', 0, PARAM_INT);
$deactivate = optional_param('lock', 0, PARAM_INT);
$sortby = optional_param('sort', 'name', PARAM_ALPHA);
$sorthow = optional_param('dir', 'ASC', PARAM_ALPHA);
$confirm = optional_param('confirm', false, PARAM_BOOL);
$delete = optional_param('delete', 0, PARAM_INT);
+$archive = optional_param('archive', 0, PARAM_INT);
$msg = optional_param('msg', '', PARAM_TEXT);
if (!in_array($sortby, array('name', 'status'))) {
$PAGE->requires->js_init_call('check_site_access', null, false);
$output = $PAGE->get_renderer('core', 'badges');
-if ($delete && has_capability('moodle/badges:deletebadge', $PAGE->context)) {
- $badge = new badge($delete);
+if (($delete || $archive) && has_capability('moodle/badges:deletebadge', $PAGE->context)) {
+ $badgeid = ($archive != 0) ? $archive : $delete;
+ $badge = new badge($badgeid);
if (!$confirm) {
echo $output->header();
- echo $output->confirm(
- get_string('delconfirm', 'badges', $badge->name),
- new moodle_url($PAGE->url, array('delete' => $badge->id, 'confirm' => 1)),
- $returnurl
- );
+ // Archive this badge?
+ echo $output->heading(get_string('archivebadge', 'badges', $badge->name));
+ $archivebutton = $output->single_button(
+ new moodle_url($PAGE->url, array('archive' => $badge->id, 'confirm' => 1)),
+ get_string('archiveconfirm', 'badges'));
+ echo $output->box(get_string('archivehelp', 'badges') . $archivebutton, 'generalbox');
+
+ // Delete this badge?
+ echo $output->heading(get_string('delbadge', 'badges', $badge->name));
+ $deletebutton = $output->single_button(
+ new moodle_url($PAGE->url, array('delete' => $badge->id, 'confirm' => 1)),
+ get_string('delconfirm', 'badges'));
+ echo $output->box(get_string('deletehelp', 'badges') . $deletebutton, 'generalbox');
+
+ // Go back.
+ echo $output->action_link($returnurl, get_string('cancel'));
+
echo $output->footer();
die();
} else {
require_sesskey();
- $badge->delete();
+ $archiveonly = ($archive != 0) ? true : false;
+ $badge->delete($archiveonly);
redirect($returnurl);
}
}
in all criteria classes. This method returns an array consisting of SQL JOIN statement, WHERE conditions,
and any parameters that might be required. The results are used in lib/badgeslib.php in review_all_criteria()
to reduce to the minimum the number of users to review and award badges.
-
* New optional parameter $filtered in review() allows to indicate that some expensive checks can be skipped
if the list of users has been initially filtered based on met criteria.
+* New optional parameter $archive in delete() in badge class in badgeslib.php
+ allows to indicate that a badge should be archived instead of fully deleted.
+ If this parameter is set to FALSE, a badge will all its information, criteria,
+ and awards will be removed from the database.
$this->content->footer = '';
$this->page->settingsnav->initialise();
- $node = $this->page->settingsnav->get('root', navigation_node::TYPE_SETTING);
+ $node = $this->page->settingsnav->get('root', navigation_node::TYPE_SITE_ADMIN);
if (!$node || !$node->contains_active_node()) {
return $this->content;
}
--- /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/>.
+
+/**
+ * block_comments comment created event.
+ *
+ * @package block_comments
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment created event.
+ *
+ * @package block_comments
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_created extends \core\event\comment_created {
+ // No need to override any method.
+}
--- /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/>.
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package block_comments
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace block_comments\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * block_comments comment deleted event.
+ *
+ * @package block_comments
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class comment_deleted extends \core\event\comment_deleted {
+ // No need to override any method.
+}
--- /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/>.
+
+/**
+ * Events tests.
+ *
+ * @package block_comments
+ * @category test
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Events tests class.
+ *
+ * @package block_comments
+ * @category test
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class block_comments_events_testcase extends advanced_testcase {
+ /** @var stdClass Keeps course object */
+ private $course;
+
+ /** @var stdClass Keeps wiki object */
+ private $wiki;
+
+ /**
+ * Setup test data.
+ */
+ public function setUp() {
+ $this->resetAfterTest();
+ $this->setAdminUser();
+
+ // Create course and wiki.
+ $this->course = $this->getDataGenerator()->create_course();
+ $this->wiki = $this->getDataGenerator()->create_module('wiki', array('course' => $this->course->id));
+ }
+
+ /**
+ * Test comment_created event.
+ */
+ public function test_comment_created() {
+ global $CFG;
+
+ require_once($CFG->dirroot . '/comment/lib.php');
+
+ // Comment on course page.
+ $context = context_course::instance($this->course->id);
+ $args = new stdClass;
+ $args->context = $context;
+ $args->course = $this->course;
+ $args->area = 'page_comments';
+ $args->itemid = 0;
+ $args->component = 'block_comments';
+ $args->linktext = get_string('showcomments');
+ $args->notoggle = true;
+ $args->autostart = true;
+ $args->displaycancel = false;
+ $comment = new comment($args);
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $comment->add('New comment');
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+ $this->assertEquals($context, $event->get_context());
+ $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+ $this->assertEquals($url, $event->get_url());
+
+ // Comments when block is on module (wiki) page.
+ $context = context_module::instance($this->wiki->id);
+ $args = new stdClass;
+ $args->context = $context;
+ $args->course = $this->course;
+ $args->area = 'page_comments';
+ $args->itemid = 0;
+ $args->component = 'block_comments';
+ $args->linktext = get_string('showcomments');
+ $args->notoggle = true;
+ $args->autostart = true;
+ $args->displaycancel = false;
+ $comment = new comment($args);
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $comment->add('New comment 1');
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\block_comments\event\comment_created', $event);
+ $this->assertEquals($context, $event->get_context());
+ $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->id));
+ $this->assertEquals($url, $event->get_url());
+ }
+
+ /**
+ * Test comment_deleted event.
+ */
+ public function test_comment_deleted() {
+ global $CFG;
+
+ require_once($CFG->dirroot . '/comment/lib.php');
+
+ // Comment on course page.
+ $context = context_course::instance($this->course->id);
+ $args = new stdClass;
+ $args->context = $context;
+ $args->course = $this->course;
+ $args->area = 'page_comments';
+ $args->itemid = 0;
+ $args->component = 'block_comments';
+ $args->linktext = get_string('showcomments');
+ $args->notoggle = true;
+ $args->autostart = true;
+ $args->displaycancel = false;
+ $comment = new comment($args);
+ $newcomment = $comment->add('New comment');
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $comment->delete($newcomment->id);
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+ $this->assertEquals($context, $event->get_context());
+ $url = new moodle_url('/course/view.php', array('id' => $this->course->id));
+ $this->assertEquals($url, $event->get_url());
+
+ // Comments when block is on module (wiki) page.
+ $context = context_module::instance($this->wiki->id);
+ $args = new stdClass;
+ $args->context = $context;
+ $args->course = $this->course;
+ $args->area = 'page_comments';
+ $args->itemid = 0;
+ $args->component = 'block_comments';
+ $args->linktext = get_string('showcomments');
+ $args->notoggle = true;
+ $args->autostart = true;
+ $args->displaycancel = false;
+ $comment = new comment($args);
+ $newcomment = $comment->add('New comment 1');
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $comment->delete($newcomment->id);
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\block_comments\event\comment_deleted', $event);
+ $this->assertEquals($context, $event->get_context());
+ $url = new moodle_url('/mod/wiki/view.php', array('id' => $this->wiki->id));
+ $this->assertEquals($url, $event->get_url());
+ }
+}
break;
case 'add mod':
$text = get_string('added', 'moodle', $cm->modfullname). '<br />'.
- html_writer::link($cm->get_url(), format_string($cm->name, true));
+ html_writer::link($cm->url, format_string($cm->name, true));
break;
case 'update mod':
$text = get_string('updated', 'moodle', $cm->modfullname). '<br />'.
- html_writer::link($cm->get_url(), format_string($cm->name, true));
+ html_writer::link($cm->url, format_string($cm->name, true));
break;
default:
return '';
$content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
$instancename = $cm->get_formatted_name();
- if (!($url = $cm->get_url())) {
+ if (!($url = $cm->url)) {
$this->content->items[] = $content;
$this->content->icons[] = '';
} else {
$instancename = $mod->get_formatted_name();
$linkcss = $mod->visible ? '' : ' class="dimmed" ';
- if (!($url = $mod->get_url())) {
+ if (!($url = $mod->url)) {
$this->content->items[] = $content . $editbuttons;
$this->content->icons[] = '';
} else {
$content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
$instancename = $cm->get_formatted_name();
- if (!($url = $cm->get_url())) {
+ if (!($url = $cm->url)) {
$this->content->items[] = $content;
$this->content->icons[] = '';
} else {
$linkcss = $mod->visible ? '' : ' class="dimmed" ';
- if (!($url = $mod->get_url())) {
+ if (!($url = $mod->url)) {
$this->content->items[] = $content . $editbuttons;
$this->content->icons[] = '';
} else {
public function test_blog_entries_viewed_event() {
$this->setAdminUser();
- $this->resetAfterTest();
+
$other = array('entryid' => $this->postid, 'tagid' => $this->tagid, 'userid' => $this->userid, 'modid' => $this->cmid,
'groupid' => $this->groupid, 'courseid' => $this->courseid, 'search' => 'search', 'fromstart' => 2);
$arr = array(SITEID, 'blog', 'view', $url2->out(), 'view blog entry');
$this->assertEventLegacyLogData($arr, $event);
}
+
+ /**
+ * Test comment_created event.
+ */
+ public function test_blog_comment_created_event() {
+ global $USER, $CFG;
+
+ $this->setAdminUser();
+
+ require_once($CFG->dirroot . '/comment/lib.php');
+ $context = context_user::instance($USER->id);
+
+ $cmt = new stdClass();
+ $cmt->context = $context;
+ $cmt->courseid = $this->courseid;
+ $cmt->area = 'format_blog';
+ $cmt->itemid = $this->postid;
+ $cmt->showcount = 1;
+ $cmt->component = 'blog';
+ $manager = new comment($cmt);
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $manager->add("New comment");
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\core\event\blog_comment_created', $event);
+ $this->assertEquals($context, $event->get_context());
+ $this->assertEquals($this->postid, $event->other['itemid']);
+ $url = new moodle_url('/blog/index.php', array('entryid' => $this->postid));
+ $this->assertEquals($url, $event->get_url());
+ }
+
+ /**
+ * Test comment_deleted event.
+ */
+ public function test_blog_comment_deleted_event() {
+ global $USER, $CFG;
+
+ $this->setAdminUser();
+
+ require_once($CFG->dirroot . '/comment/lib.php');
+ $context = context_user::instance($USER->id);
+
+ $cmt = new stdClass();
+ $cmt->context = $context;
+ $cmt->courseid = $this->courseid;
+ $cmt->area = 'format_blog';
+ $cmt->itemid = $this->postid;
+ $cmt->showcount = 1;
+ $cmt->component = 'blog';
+ $manager = new comment($cmt);
+ $newcomment = $manager->add("New comment");
+
+ // Triggering and capturing the event.
+ $sink = $this->redirectEvents();
+ $manager->delete($newcomment->id);
+ $events = $sink->get_events();
+ $this->assertCount(1, $events);
+ $event = reset($events);
+
+ // Checking that the event contains the expected values.
+ $this->assertInstanceOf('\core\event\blog_comment_deleted', $event);
+ $this->assertEquals($context, $event->get_context());
+ $this->assertEquals($this->postid, $event->other['itemid']);
+ $url = new moodle_url('/blog/index.php', array('entryid' => $this->postid));
+ $this->assertEquals($url, $event->get_url());
+ }
}
return (!empty($this->definition));
}
- /**
- * Returns true if this is ready.
- * @return bool
- */
- public function is_ready() {
- return true;
- }
-
/**
* Returns true the given mode is supported.
* @param int $mode
public function create_cache(cache_definition $definition) {
$class = $definition->get_cache_class();
$stores = cache_helper::get_stores_suitable_for_definition($definition);
+ foreach ($stores as $key => $store) {
+ if (!$store::are_requirements_met()) {
+ unset($stores[$key]);
+ }
+ }
if (count($stores) === 0) {
// Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
$stores[] = $this->create_dummy_store($definition);
/**
* Creates a store instance given its name and configuration.
*
- * If the store has already been instantiated then the original objetc will be returned. (reused)
+ * If the store has already been instantiated then the original object will be returned. (reused)
*
* @param string $name The name of the store (must be unique remember)
* @param array $details
$store = new $class($details['name'], $details['configuration']);
$this->stores[$name] = $store;
}
+ /* @var cache_store $store */
$store = $this->stores[$name];
if (!$store->is_ready() || !$store->is_supported_mode($definition->get_mode())) {
return false;
$class = $store['class'];
// Found the store: is it ready?
+ /* @var cache_store $instance */
$instance = new $class($store['name'], $store['configuration']);
if (!$instance->is_ready()) {
unset($instance);
* Returns true if this cache store instance is ready to use.
* @return bool
*/
- abstract public function is_ready();
+ public function is_ready() {
+ return forward_static_call(array($this, 'are_requirements_met'));
+ }
/**
* Retrieves an item from the cache store given its key.
return (is_array($this->store));
}
- /**
- * Returns true if this store instance is ready to be used.
- * @return bool
- */
- public function is_ready() {
- return true;
- }
-
/**
* Retrieves an item from the cache store given its key.
*
return (is_array($this->store));
}
- /**
- * Returns true if this store instance is ready to be used.
- * @return bool
- */
- public function is_ready() {
- return true;
- }
-
/**
* Retrieves an item from the cache store given its key.
*
This files describes API changes in /cache/stores/* - cache store plugins.
Information provided here is intended especially for developers.
+=== 2.7 ===
+* cache_store::is_ready is no longer abstract, calling cache_store::are_requirements_met by default.
+
=== 2.6 ===
* All cache instances are recorded and subsequent requests are given a reference to the original instance.
* The persistent option for the cache definition has been deprecated. Please use the staticacceleration option instead.
$newcmt->time = userdate($newcmt->timecreated, $newcmt->strftimeformat);
// Trigger comment created event.
- $eventclassname = '\\' . $this->component . '\\event\comment_created';
+ if (core_component::is_core_subsystem($this->component)) {
+ $eventclassname = '\\core\\event\\' . $this->component . '_comment_created';
+ } else {
+ $eventclassname = '\\' . $this->component . '\\event\comment_created';
+ }
if (class_exists($eventclassname)) {
$event = $eventclassname::create(
array(
}
$DB->delete_records('comments', array('id'=>$commentid));
// Trigger comment delete event.
- $eventclassname = '\\' . $this->component . '\\event\comment_deleted';
+ if (core_component::is_core_subsystem($this->component)) {
+ $eventclassname = '\\core\\event\\' . $this->component . '_comment_deleted';
+ } else {
+ $eventclassname = '\\' . $this->component . '\\event\comment_deleted';
+ }
if (class_exists($eventclassname)) {
$event = $eventclassname::create(
array(
//=========================================================================
// 10. SECRET PASSWORD SALT
//=========================================================================
-// A single site-wide password salt is no longer required *unless* you are
-// upgrading an older version of Moodle (prior to 2.5), or if you are using
-// a PHP version below 5.3.7. If upgrading, keep any values from your old
-// config.php file. If you are using PHP < 5.3.7 set to a long random string
-// below:
+// A site-wide password salt is no longer used in new installations.
+// If upgrading from 2.6 or older, keep all existing salts in config.php file.
//
// $CFG->passwordsaltmain = 'a_very_long_random_string_of_characters#@6&*1';
//
);
}
+ if ($category->can_restore_courses_into()) {
+ $actions['restore'] = array(
+ 'url' => new \moodle_url('/backup/restorefile.php', array('contextid' => $category->get_context()->id)),
+ 'icon' => new \pix_icon('i/restore', new \lang_string('restorecourse', 'admin')),
+ 'string' => new \lang_string('restorecourse', 'admin')
+ );
+ }
+
return $actions;
}
var result = JSON.parse(xhr.responseText);
if (result) {
if (result.error == 0) {
- // All OK - update the dummy element
- if (result.content) {
- // A label
- resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
- } else {
- // Not a label
- resel.icon.src = result.icon;
- resel.a.href = result.link;
- resel.namespan.innerHTML = result.name;
-
- if (!parseInt(result.visible, 10)) {
- resel.a.className = 'dimmed';
- }
-
- if (result.groupingname) {
- resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
- } else {
- resel.div.removeChild(resel.groupingspan);
- }
-
- resel.div.removeChild(resel.progressouter);
- resel.indentdiv.innerHTML += result.commands;
- if (result.onclick) {
- resel.a.onclick = result.onclick;
- }
- if (self.Y.UA.gecko > 0) {
- // Fix a Firefox bug which makes sites with a '~' in their wwwroot
- // log the user out when clicking on the link (before refreshing the page).
- resel.div.innerHTML = unescape(resel.div.innerHTML);
- }
+ // All OK - replace the dummy element.
+ resel.li.outerHTML = result.fullcontent;
+ if (self.Y.UA.gecko > 0) {
+ // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+ // log the user out when clicking on the link (before refreshing the page).
+ resel.li.outerHTML = unescape(resel.li.outerHTML);
}
- resel.li.id = result.elementid;
self.add_editing(result.elementid);
} else {
// Error - remove the dummy element
var result = JSON.parse(xhr.responseText);
if (result) {
if (result.error == 0) {
- // All OK - update the dummy element
- if (result.content) {
- // A label
- resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
- } else {
- // Not a label
- resel.icon.src = result.icon;
- resel.a.href = result.link;
- resel.namespan.innerHTML = result.name;
-
- if (!parseInt(result.visible, 10)) {
- resel.a.className = 'dimmed';
- }
-
- if (result.groupingname) {
- resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
- } else {
- resel.div.removeChild(resel.groupingspan);
- }
-
- resel.div.removeChild(resel.progressouter);
- resel.div.innerHTML += result.commands;
- if (result.onclick) {
- resel.a.onclick = result.onclick;
- }
- if (self.Y.UA.gecko > 0) {
- // Fix a Firefox bug which makes sites with a '~' in their wwwroot
- // log the user out when clicking on the link (before refreshing the page).
- resel.div.innerHTML = unescape(resel.div.innerHTML);
- }
+ // All OK - replace the dummy element.
+ resel.li.outerHTML = result.fullcontent;
+ if (self.Y.UA.gecko > 0) {
+ // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+ // log the user out when clicking on the link (before refreshing the page).
+ resel.li.outerHTML = unescape(resel.li.outerHTML);
}
- resel.li.id = result.elementid;
- self.add_editing(result.elementid, sectionnumber);
+ self.add_editing(result.elementid);
} else {
// Error - remove the dummy element
resel.parent.removeChild(resel.li);
*/
protected function send_response($mod) {
global $OUTPUT, $PAGE;
- $courserenderer = $PAGE->get_renderer('core', 'course');
$resp = new stdClass();
$resp->error = self::ERROR_OK;
- $resp->icon = $mod->get_icon_url()->out();
- $resp->name = $mod->name;
- if ($mod->has_view()) {
- $resp->link = $mod->get_url()->out();
- } else {
- $resp->link = null;
- }
- $resp->content = $mod->get_content();
- $resp->elementid = 'module-'.$mod->id;
- $actions = course_get_cm_edit_actions($mod, 0, $mod->sectionnum);
- $resp->commands = ' '. $courserenderer->course_section_cm_edit_actions($actions, $mod);
- $resp->onclick = $mod->get_on_click();
- $resp->visible = $mod->visible;
-
- // If using groupings, then display grouping name.
- if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
- $groupings = groups_get_all_groupings($this->course->id);
- $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
- }
+ $resp->elementid = 'module-' . $mod->id;
+
+ $courserenderer = $PAGE->get_renderer('core', 'course');
+ $completioninfo = new completion_info($this->course);
+ $info = get_fast_modinfo($this->course);
+ $sr = null;
+ $modulehtml = $courserenderer->course_section_cm($this->course, $completioninfo,
+ $mod, null, array());
+ $resp->fullcontent = $courserenderer->course_section_cm_list_item($this->course, $completioninfo, $mod, $sr);
echo $OUTPUT->header();
echo json_encode($resp);
$modcontext = context_module::instance($cm->id);
if (!empty($cm->showdescription) or $cm->modname == 'label') {
- // We want to use the external format. However from reading get_formatted_content(), get_content() format is always FORMAT_HTML.
- list($module['description'], $descriptionformat) = external_format_text($cm->get_content(),
+ // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
+ list($module['description'], $descriptionformat) = external_format_text($cm->content,
FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id);
}
//url of the module
- $url = $cm->get_url();
+ $url = $cm->url;
if ($url) { //labels don't have url
- $module['url'] = $cm->get_url()->out(false);
+ $module['url'] = $url->out(false);
}
$canviewhidden = has_capability('moodle/course:viewhiddenactivities',
if (!$cm->uservisible) {
return null;
}
- $action = $cm->get_url();
+ $action = $cm->url;
if (!$action) {
// Do not add to navigation activity without url (i.e. labels).
return null;
// Student views an empty course page.
return;
}
- } else if (!$cm->uservisible || !$cm->get_url()) {
+ } else if (!$cm->uservisible || !$cm->url) {
// Activity is set but not visible to current user or does not have url.
// Display course page (either empty or with availability restriction info).
return;
} else {
// Everything is set up and accessible, redirect to the activity page!
- redirect($cm->get_url());
+ redirect($cm->url);
}
}
}
);
// Include course dragdrop
- if ($course->id != $SITE->id) {
+ if (course_format_uses_sections($course->format)) {
$PAGE->requires->yui_module('moodle-course-dragdrop', 'M.course.init_section_dragdrop',
array(array(
'courseid' => $course->id,
'emptydragdropregion'
), 'moodle');
- // Include format-specific strings
- if ($course->id != $SITE->id) {
+ // Include section-specific strings for formats which support sections.
+ if (course_format_uses_sections($course->format)) {
$PAGE->requires->strings_for_js(array(
'showfromothers',
'hidefromothers',
print_error('usernotincourse');
}
$context = $coursecontext;
+
+ // Check if course has SEPARATEGROUPS and user is part of that group.
+ if (groups_get_course_groupmode($course) == SEPARATEGROUPS &&
+ !has_capability('moodle/site:accessallgroups', $context)) {
+ $samegroup = false;
+ if ($groups = groups_get_all_groups($course->id, $USER->id)) {
+ foreach ($groups as $group) {
+ if (groups_is_member($group->id, $userid)) {
+ $samegroup = true;
+ break;
+ }
+ }
+ }
+ if (!$samegroup) {
+ print_error('nologinas');
+ }
+ }
}
// Login as this user and return to course home page.
$formcontent .= html_writer::start_tag('div', array('id' => 'typeformdiv'));
$formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'id' => 'course',
'name' => 'course', 'value' => $course->id));
- $formcontent .= html_writer::tag('input', '',
- array('type' => 'hidden', 'class' => 'jump', 'name' => 'jump', 'value' => ''));
$formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'name' => 'sesskey',
'value' => sesskey()));
$formcontent .= html_writer::end_tag('div');
// nothing to be displayed to the user
return $output;
}
- $url = $mod->get_url();
+ $url = $mod->url;
if (!$url) {
return $output;
}
// Get on-click attribute value if specified and decode the onclick - it
// has already been encoded for display (puke).
- $onclick = htmlspecialchars_decode($mod->get_on_click(), ENT_QUOTES);
+ $onclick = htmlspecialchars_decode($mod->onclick, ENT_QUOTES);
$groupinglabel = '';
if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', context_course::instance($mod->course))) {
} else {
$textclasses .= ' dimmed_text';
}
- if ($mod->get_url()) {
+ if ($mod->url) {
if ($content) {
// If specified, display extra content after link.
$output = html_writer::tag('div', $content, array('class' =>
public function course_section_cm_list_item($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) {
$output = '';
if ($modulehtml = $this->course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions)) {
- $modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->get_extra_classes();
+ $modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->extraclasses;
$output .= html_writer::tag('li', $modulehtml, array('class' => $modclasses, 'id' => 'module-' . $mod->id));
}
return $output;
*
* This function calls:
* {@link core_course_renderer::course_section_cm_name()}
- * {@link cm_info::get_after_link()}
* {@link core_course_renderer::course_section_cm_text()}
* {@link core_course_renderer::course_section_cm_availability()}
* {@link core_course_renderer::course_section_cm_completion()}
}
// Module can put text after the link (e.g. forum unread)
- $output .= $mod->get_after_link();
+ $output .= $mod->afterlink;
// Closing the tag which contains everything but edit icons. Content part of the module should not be part of this.
$output .= html_writer::end_tag('div'); // .activityinstance
// it should work similarly (at least in terms of ordering) to an
// activity.
$contentpart = $this->course_section_cm_text($mod, $displayoptions);
- $url = $mod->get_url();
+ $url = $mod->url;
if (empty($url)) {
$output .= $contentpart;
}
if ($this->page->user_is_editing()) {
$editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn);
$modicons .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions);
- $modicons .= $mod->get_after_edit_icons();
+ $modicons .= $mod->afterediticons;
}
$modicons .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions);
foreach($firstsection['modules'] as $module) {
if ($module['id'] == $forumcm->id and $module['modname'] == 'forum') {
$cm = $modinfo->cms[$forumcm->id];
- $formattedtext = format_text($cm->get_content(), FORMAT_HTML,
+ $formattedtext = format_text($cm->content, FORMAT_HTML,
array('noclean' => true, 'para' => false, 'filter' => false));
$this->assertEquals($formattedtext, $module['description']);
$testexecuted = $testexecuted + 1;
} else if ($module['id'] == $labelcm->id and $module['modname'] == 'label') {
$cm = $modinfo->cms[$labelcm->id];
- $formattedtext = format_text($cm->get_content(), FORMAT_HTML,
+ $formattedtext = format_text($cm->content, FORMAT_HTML,
array('noclean' => true, 'para' => false, 'filter' => false));
$this->assertEquals($formattedtext, $module['description']);
$testexecuted = $testexecuted + 1;
+++ /dev/null
-YUI.add('moodle-course-coursebase', function(Y) {
-
- /**
- * The coursebase class
- */
- var COURSEBASENAME = 'course-coursebase';
-
- var COURSEBASE = function() {
- COURSEBASE.superclass.constructor.apply(this, arguments);
- }
-
- Y.extend(COURSEBASE, Y.Base, {
- // Registered Modules
- registermodules : [],
-
- /**
- * Initialize the coursebase module
- */
- initializer : function(config) {
- // We don't actually perform any work here
- },
-
- /**
- * Register a new Javascript Module
- *
- * @param object The instantiated module to call functions on
- */
- register_module : function(object) {
- this.registermodules.push(object);
- },
-
- /**
- * Invoke the specified function in all registered modules with the given arguments
- *
- * @param functionname The name of the function to call
- * @param args The argument supplied to the function
- */
- invoke_function : function(functionname, args) {
- for (module in this.registermodules) {
- if (functionname in this.registermodules[module]) {
- this.registermodules[module][functionname](args);
- }
- }
- }
- },
- {
- NAME : COURSEBASENAME,
- ATTRS : {}
- }
- );
-
- // Ensure that M.course exists and that coursebase is initialised correctly
- M.course = M.course || {};
- M.course.coursebase = M.course.coursebase || new COURSEBASE();
-
- // Abstract functions that needs to be defined per format (course/format/somename/format.js)
- M.course.format = M.course.format || {}
-
- /**
- * Swap section (should be defined in format.js if requred)
- *
- * @param {YUI} Y YUI3 instance
- * @param {string} node1 node to swap to
- * @param {string} node2 node to swap with
- * @return {NodeList} section list
- */
- M.course.format.swap_sections = M.course.format.swap_sections || function(Y, node1, node2) {
- return null;
- }
-
- /**
- * Process sections after ajax response (should be defined in format.js)
- * If some response is expected, we pass it over to format, as it knows better
- * hot to process it.
- *
- * @param {YUI} Y YUI3 instance
- * @param {NodeList} list of sections
- * @param {array} response ajax response
- * @param {string} sectionfrom first affected section
- * @param {string} sectionto last affected section
- * @return void
- */
- M.course.format.process_sections = M.course.format.process_sections || function(Y, sectionlist, response, sectionfrom, sectionto) {
- return null;
- }
-
- /**
- * Get sections config for this format, for examples see function definition
- * in the formats.
- *
- * @return {object} section list configuration
- */
- M.course.format.get_config = M.course.format.get_config || function() {
- return {
- container_node : null, // compulsory
- container_class : null, // compulsory
- section_wrapper_node : null, // optional
- section_wrapper_class : null, // optional
- section_node : null, // compulsory
- section_class : null // compulsory
- }
- }
-
- /**
- * Get section list for this format (usually items inside container_node.container_class selector)
- *
- * @param {YUI} Y YUI3 instance
- * @return {string} section selector
- */
- M.course.format.get_section_selector = M.course.format.get_section_selector || function(Y) {
- var config = M.course.format.get_config();
- if (config.section_node && config.section_class) {
- return config.section_node + '.' + config.section_class;
- }
- console.log('section_node and section_class are not defined in M.course.format.get_config');
- return null;
- }
-
- /**
- * Get section wraper for this format (only used in case when each
- * container_node.container_class node is wrapped in some other element).
- *
- * @param {YUI} Y YUI3 instance
- * @return {string} section wrapper selector or M.course.format.get_section_selector
- * if section_wrapper_node and section_wrapper_class are not defined in the format config.
- */
- M.course.format.get_section_wrapper = M.course.format.get_section_wrapper || function(Y) {
- var config = M.course.format.get_config();
- if (config.section_wrapper_node && config.section_wrapper_class) {
- return config.section_wrapper_node + '.' + config.section_wrapper_class;
- }
- return M.course.format.get_section_selector(Y);
- }
-
- /**
- * Get the tag of container node
- *
- * @return {string} tag of container node.
- */
- M.course.format.get_containernode = M.course.format.get_containernode || function() {
- var config = M.course.format.get_config();
- if (config.container_node) {
- return config.container_node;
- } else {
- console.log('container_node is not defined in M.course.format.get_config');
- }
- }
-
- /**
- * Get the class of container node
- *
- * @return {string} class of the container node.
- */
- M.course.format.get_containerclass = M.course.format.get_containerclass || function() {
- var config = M.course.format.get_config();
- if (config.container_class) {
- return config.container_class;
- } else {
- console.log('container_class is not defined in M.course.format.get_config');
- }
- }
-
- /**
- * Get the tag of draggable node (section wrapper if exists, otherwise section)
- *
- * @return {string} tag of the draggable node.
- */
- M.course.format.get_sectionwrappernode = M.course.format.get_sectionwrappernode || function() {
- var config = M.course.format.get_config();
- if (config.section_wrapper_node) {
- return config.section_wrapper_node;
- } else {
- return config.section_node;
- }
- }
-
- /**
- * Get the class of draggable node (section wrapper if exists, otherwise section)
- *
- * @return {string} class of the draggable node.
- */
- M.course.format.get_sectionwrapperclass = M.course.format.get_sectionwrapperclass || function() {
- var config = M.course.format.get_config();
- if (config.section_wrapper_class) {
- return config.section_wrapper_class;
- } else {
- return config.section_class;
- }
- }
-
- /**
- * Get the tag of section node
- *
- * @return {string} tag of section node.
- */
- M.course.format.get_sectionnode = M.course.format.get_sectionnode || function() {
- var config = M.course.format.get_config();
- if (config.section_node) {
- return config.section_node;
- } else {
- console.log('section_node is not defined in M.course.format.get_config');
- }
- }
-
- /**
- * Get the class of section node
- *
- * @return {string} class of the section node.
- */
- M.course.format.get_sectionclass = M.course.format.get_sectionclass || function() {
- var config = M.course.format.get_config();
- if (config.section_class) {
- return config.section_class;
- } else {
- console.log('section_class is not defined in M.course.format.get_config');
- }
-
- }
-
-},
-'@VERSION@', {
- requires : ['base', 'node']
-}
-);
+++ /dev/null
-YUI.add('moodle-course-dragdrop', function(Y) {
-
- var CSS = {
- ACTIONAREA: '.actions',
- ACTIVITY : 'activity',
- ACTIVITYINSTANCE : 'activityinstance',
- CONTENT : 'content',
- COURSECONTENT : 'course-content',
- EDITINGMOVE : 'editing_move',
- ICONCLASS : 'iconsmall',
- JUMPMENU : 'jumpmenu',
- LEFT : 'left',
- LIGHTBOX : 'lightbox',
- MOVEDOWN : 'movedown',
- MOVEUP : 'moveup',
- PAGECONTENT : 'page-content',
- RIGHT : 'right',
- SECTION : 'section',
- SECTIONADDMENUS : 'section_add_menus',
- SECTIONHANDLE : 'section-handle',
- SUMMARY : 'summary',
- SECTIONDRAGGABLE: 'sectiondraggable'
- };
-
- var DRAGSECTION = function() {
- DRAGSECTION.superclass.constructor.apply(this, arguments);
- };
- Y.extend(DRAGSECTION, M.core.dragdrop, {
- sectionlistselector : null,
-
- initializer : function() {
- // Set group for parent class
- this.groups = [ CSS.SECTIONDRAGGABLE ];
- this.samenodeclass = M.course.format.get_sectionwrapperclass();
- this.parentnodeclass = M.course.format.get_containerclass();
-
- // Check if we are in single section mode
- if (Y.Node.one('.'+CSS.JUMPMENU)) {
- return false;
- }
- // Initialise sections dragging
- this.sectionlistselector = M.course.format.get_section_wrapper(Y);
- if (this.sectionlistselector) {
- this.sectionlistselector = '.'+CSS.COURSECONTENT+' '+this.sectionlistselector;
-
- this.setup_for_section(this.sectionlistselector);
-
- // Make each li element in the lists of sections draggable
- var del = new Y.DD.Delegate({
- container: '.'+CSS.COURSECONTENT,
- nodes: '.' + CSS.SECTIONDRAGGABLE,
- target: true,
- handles: ['.'+CSS.LEFT],
- dragConfig: {groups: this.groups}
- });
- del.dd.plug(Y.Plugin.DDProxy, {
- // Don't move the node at the end of the drag
- moveOnEnd: false
- });
- del.dd.plug(Y.Plugin.DDConstrained, {
- // Keep it inside the .course-content
- constrain: '#'+CSS.PAGECONTENT,
- stickY: true
- });
- del.dd.plug(Y.Plugin.DDWinScroll);
- }
- },
-
- /**
- * Apply dragdrop features to the specified selector or node that refers to section(s)
- *
- * @param baseselector The CSS selector or node to limit scope to
- * @return void
- */
- setup_for_section : function(baseselector) {
- Y.Node.all(baseselector).each(function(sectionnode) {
- // Determine the section ID
- var sectionid = Y.Moodle.core_course.util.section.getId(sectionnode);
-
- // We skip the top section as it is not draggable
- if (sectionid > 0) {
- // Remove move icons
- var movedown = sectionnode.one('.'+CSS.RIGHT+' a.'+CSS.MOVEDOWN);
- var moveup = sectionnode.one('.'+CSS.RIGHT+' a.'+CSS.MOVEUP);
-
- // Add dragger icon
- var title = M.util.get_string('movesection', 'moodle', sectionid);
- var cssleft = sectionnode.one('.'+CSS.LEFT);
-
- if ((movedown || moveup) && cssleft) {
- cssleft.setStyle('cursor', 'move');
- cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
-
- if (moveup) {
- moveup.remove();
- }
- if (movedown) {
- movedown.remove();
- }
-
- // This section can be moved - add the class to indicate this to Y.DD.
- sectionnode.addClass(CSS.SECTIONDRAGGABLE);
- }
- }
- }, this);
- },
-
- /*
- * Drag-dropping related functions
- */
- drag_start : function(e) {
- // Get our drag object
- var drag = e.target;
- // Creat a dummy structure of the outer elemnents for clean styles application
- var containernode = Y.Node.create('<'+M.course.format.get_containernode()+'></'+M.course.format.get_containernode()+'>');
- containernode.addClass(M.course.format.get_containerclass());
- var sectionnode = Y.Node.create('<'+ M.course.format.get_sectionwrappernode()+'></'+ M.course.format.get_sectionwrappernode()+'>');
- sectionnode.addClass( M.course.format.get_sectionwrapperclass());
- sectionnode.setStyle('margin', 0);
- sectionnode.setContent(drag.get('node').get('innerHTML'));
- containernode.appendChild(sectionnode);
- drag.get('dragNode').setContent(containernode);
- drag.get('dragNode').addClass(CSS.COURSECONTENT);
- },
-
- drag_dropmiss : function(e) {
- // Missed the target, but we assume the user intended to drop it
- // on the last last ghost node location, e.drag and e.drop should be
- // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
- this.drop_hit(e);
- },
-
- get_section_index: function(node) {
- var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.course.format.get_section_selector(Y),
- sectionList = Y.all(sectionlistselector),
- nodeIndex = sectionList.indexOf(node),
- zeroIndex = sectionList.indexOf(Y.one('#section-0'));
-
- return (nodeIndex - zeroIndex);
- },
-
- drop_hit : function(e) {
- var drag = e.drag;
-
- // Get references to our nodes and their IDs.
- var dragnode = drag.get('node'),
- dragnodeid = Y.Moodle.core_course.util.section.getId(dragnode),
- loopstart = dragnodeid,
-
- dropnodeindex = this.get_section_index(dragnode),
- loopend = dropnodeindex;
-
- if (dragnodeid === dropnodeindex) {
- Y.log("Skipping move - same location moving " + dragnodeid + " to " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
- return;
- }
-
- Y.log("Moving from position " + dragnodeid + " to position " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
-
- if (loopstart > loopend) {
- // If we're going up, we need to swap the loop order
- // because loops can't go backwards.
- loopstart = dropnodeindex;
- loopend = dragnodeid;
- }
-
- // Get the list of nodes.
- drag.get('dragNode').removeClass(CSS.COURSECONTENT);
- var sectionlist = Y.Node.all(this.sectionlistselector);
-
- // Add a lightbox if it's not there.
- var lightbox = M.util.add_lightbox(Y, dragnode);
-
- // Handle any variables which we must pass via AJAX.
- var params = {},
- pageparams = this.get('config').pageparams,
- varname;
-
- for (varname in pageparams) {
- if (!pageparams.hasOwnProperty(varname)) {
- continue;
- }
- params[varname] = pageparams[varname];
- }
-
- // Prepare request parameters
- params.sesskey = M.cfg.sesskey;
- params.courseId = this.get('courseid');
- params['class'] = 'section';
- params.field = 'move';
- params.id = dragnodeid;
- params.value = dropnodeindex;
-
- // Perform the AJAX request.
- var uri = M.cfg.wwwroot + this.get('ajaxurl');
- Y.io(uri, {
- method: 'POST',
- data: params,
- on: {
- start : function() {
- lightbox.show();
- },
- success: function(tid, response) {
- // Update section titles, we can't simply swap them as
- // they might have custom title
- try {
- var responsetext = Y.JSON.parse(response.responseText);
- if (responsetext.error) {
- new M.core.ajaxException(responsetext);
- }
- M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
- } catch (e) {}
-
- // Update all of the section IDs - first unset them, then set them
- // to avoid duplicates in the DOM.
- var index;
-
- // Classic bubble sort algorithm is applied to the section
- // nodes between original drag node location and the new one.
- var swapped = false;
- do {
- swapped = false;
- for (index = loopstart; index <= loopend; index++) {
- if (Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) >
- Y.Moodle.core_course.util.section.getId(sectionlist.item(index))) {
- Y.log("Swapping " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) +
- " with " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index)));
- // Swap section id.
- var sectionid = sectionlist.item(index - 1).get('id');
- sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id'));
- sectionlist.item(index).set('id', sectionid);
-
- // See what format needs to swap.
- M.course.format.swap_sections(Y, index - 1, index);
-
- // Update flag.
- swapped = true;
- }
- }
- loopend = loopend - 1;
- } while (swapped);
-
- window.setTimeout(function() {
- lightbox.hide();
- }, 250);
- },
-
- failure: function(tid, response) {
- this.ajax_failure(response);
- lightbox.hide();
- }
- },
- context:this
- });
- }
-
- }, {
- NAME : 'course-dragdrop-section',
- ATTRS : {
- courseid : {
- value : null
- },
- ajaxurl : {
- 'value' : 0
- },
- config : {
- 'value' : 0
- }
- }
- });
-
- var DRAGRESOURCE = function() {
- DRAGRESOURCE.superclass.constructor.apply(this, arguments);
- };
- Y.extend(DRAGRESOURCE, M.core.dragdrop, {
- initializer : function(params) {
- // Set group for parent class
- this.groups = ['resource'];
- this.samenodeclass = CSS.ACTIVITY;
- this.parentnodeclass = CSS.SECTION;
- this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS, true);
-
- // Go through all sections
- var sectionlistselector = M.course.format.get_section_selector(Y);
- if (sectionlistselector) {
- sectionlistselector = '.'+CSS.COURSECONTENT+' '+sectionlistselector;
- this.setup_for_section(sectionlistselector);
-
- // Initialise drag & drop for all resources/activities
- var nodeselector = sectionlistselector.slice(CSS.COURSECONTENT.length+2)+' li.'+CSS.ACTIVITY;
- var del = new Y.DD.Delegate({
- container: '.'+CSS.COURSECONTENT,
- nodes: nodeselector,
- target: true,
- handles: ['.' + CSS.EDITINGMOVE],
- dragConfig: {groups: this.groups}
- });
- del.dd.plug(Y.Plugin.DDProxy, {
- // Don't move the node at the end of the drag
- moveOnEnd: false,
- cloneNode: true
- });
- del.dd.plug(Y.Plugin.DDConstrained, {
- // Keep it inside the .course-content
- constrain: '#'+CSS.PAGECONTENT
- });
- del.dd.plug(Y.Plugin.DDWinScroll);
-
- M.course.coursebase.register_module(this);
- M.course.dragres = this;
- }
- },
-
- /**
- * Apply dragdrop features to the specified selector or node that refers to section(s)
- *
- * @param baseselector The CSS selector or node to limit scope to
- * @return void
- */
- setup_for_section : function(baseselector) {
- Y.Node.all(baseselector).each(function(sectionnode) {
- var resources = sectionnode.one('.'+CSS.CONTENT+' ul.'+CSS.SECTION);
- // See if resources ul exists, if not create one
- if (!resources) {
- var resources = Y.Node.create('<ul></ul>');
- resources.addClass(CSS.SECTION);
- sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
- }
- resources.setAttribute('data-draggroups', this.groups.join(' '));
- // Define empty ul as droptarget, so that item could be moved to empty list
- var tar = new Y.DD.Drop({
- node: resources,
- groups: this.groups,
- padding: '20 0 20 0'
- });
-
- // Initialise each resource/activity in this section
- this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY);
- }, this);
- },
- /**
- * Apply dragdrop features to the specified selector or node that refers to resource(s)
- *
- * @param baseselector The CSS selector or node to limit scope to
- * @return void
- */
- setup_for_resource : function(baseselector) {
- Y.Node.all(baseselector).each(function(resourcesnode) {
- // Replace move icons
- var move = resourcesnode.one('a.'+CSS.EDITINGMOVE);
- if (move) {
- move.replace(this.resourcedraghandle.cloneNode(true));
- }
- }, this);
- },
-
- drag_start : function(e) {
- // Get our drag object
- var drag = e.target;
- drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
- drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
- },
-
- drag_dropmiss : function(e) {
- // Missed the target, but we assume the user intended to drop it
- // on the last last ghost node location, e.drag and e.drop should be
- // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
- this.drop_hit(e);
- },
-
- drop_hit : function(e) {
- var drag = e.drag;
- // Get a reference to our drag node
- var dragnode = drag.get('node');
- var dropnode = e.drop.get('node');
-
- // Add spinner if it not there
- var actionarea = dragnode.one(CSS.ACTIONAREA);
- var spinner = M.util.add_spinner(Y, actionarea);
-
- var params = {};
-
- // Handle any variables which we must pass back through to
- var pageparams = this.get('config').pageparams;
- var varname;
- for (varname in pageparams) {
- params[varname] = pageparams[varname];
- }
-
- // Prepare request parameters
- params.sesskey = M.cfg.sesskey;
- params.courseId = this.get('courseid');
- params['class'] = 'resource';
- params.field = 'move';
- params.id = Number(Y.Moodle.core_course.util.cm.getId(dragnode));
- params.sectionId = Y.Moodle.core_course.util.section.getId(dropnode.ancestor(M.course.format.get_section_wrapper(Y), true));
-
- if (dragnode.next()) {
- params.beforeId = Number(Y.Moodle.core_course.util.cm.getId(dragnode.next()));
- }
-
- // Do AJAX request
- var uri = M.cfg.wwwroot + this.get('ajaxurl');
-
- Y.io(uri, {
- method: 'POST',
- data: params,
- on: {
- start : function(tid) {
- this.lock_drag_handle(drag, CSS.EDITINGMOVE);
- spinner.show();
- },
- success: function(tid, response) {
- var responsetext = Y.JSON.parse(response.responseText);
- var params = {element: dragnode, visible: responsetext.visible};
- M.course.coursebase.invoke_function('set_visibility_resource_ui', params);
- this.unlock_drag_handle(drag, CSS.EDITINGMOVE);
- window.setTimeout(function(e) {
- spinner.hide();
- }, 250);
- },
- failure: function(tid, response) {
- this.ajax_failure(response);
- this.unlock_drag_handle(drag, CSS.SECTIONHANDLE);
- spinner.hide();
- // TODO: revert nodes location
- }
- },
- context:this
- });
- }
- }, {
- NAME : 'course-dragdrop-resource',
- ATTRS : {
- courseid : {
- value : null
- },
- ajaxurl : {
- 'value' : 0
- },
- config : {
- 'value' : 0
- }
- }
- });
-
- M.course = M.course || {};
- M.course.init_resource_dragdrop = function(params) {
- new DRAGRESOURCE(params);
- }
- M.course.init_section_dragdrop = function(params) {
- new DRAGSECTION(params);
- }
-}, '@VERSION@', {requires:['base', 'node', 'io', 'dom', 'dd', 'dd-scroll', 'moodle-core-dragdrop', 'moodle-core-notification', 'moodle-course-coursebase', 'moodle-course-util']});
+++ /dev/null
-YUI.add('moodle-course-formatchooser', function(Y) {
- var FORMATCHOOSER = function() {
- FORMATCHOOSER.superclass.constructor.apply(this, arguments);
- }
-
- Y.extend(FORMATCHOOSER, Y.Base, {
- initializer : function(params) {
- if (params && params.formid) {
- var updatebut = Y.one('#'+params.formid+' #id_updatecourseformat');
- var formatselect = Y.one('#'+params.formid+' #id_format');
- if (updatebut && formatselect) {
- updatebut.setStyle('display', 'none');
- formatselect.on('change', function() {
- updatebut.simulate('click');
- });
- }
- }
- }
- });
-
- M.course = M.course || {};
- M.course.init_formatchooser = function(params) {
- return new FORMATCHOOSER(params);
- }
-}, '@VERSION@', {requires:['base', 'node', 'node-event-simulate']});
--- /dev/null
+{
+ "name": "moodle-course-coursebase",
+ "builds": {
+ "moodle-course-coursebase": {
+ "jsfiles": [
+ "coursebase.js"
+ ]
+ }
+ }
+}
--- /dev/null
+/**
+ * The coursebase class to provide shared functionality to Modules within
+ * Moodle.
+ *
+ * @module moodle-course-coursebase
+ */
+var COURSEBASENAME = 'course-coursebase';
+
+var COURSEBASE = function() {
+ COURSEBASE.superclass.constructor.apply(this, arguments);
+};
+
+/**
+ * The coursebase class to provide shared functionality to Modules within
+ * Moodle.
+ *
+ * @class M.course.coursebase
+ * @constructor
+ */
+Y.extend(COURSEBASE, Y.Base, {
+ // Registered Modules
+ registermodules : [],
+
+ /**
+ * Register a new Javascript Module
+ *
+ * @method register_module
+ * @param {Object} The instantiated module to call functions on
+ * @chainable
+ */
+ register_module : function(object) {
+ this.registermodules.push(object);
+
+ return this;
+ },
+
+ /**
+ * Invoke the specified function in all registered modules with the given arguments
+ *
+ * @method invoke_function
+ * @param {String} functionname The name of the function to call
+ * @param {mixed} args The argument supplied to the function
+ * @chainable
+ */
+ invoke_function : function(functionname, args) {
+ var module;
+ for (module in this.registermodules) {
+ if (functionname in this.registermodules[module]) {
+ this.registermodules[module][functionname](args);
+ }
+ }
+
+ return this;
+ }
+}, {
+ NAME : COURSEBASENAME,
+ ATTRS : {}
+});
+
+// Ensure that M.course exists and that coursebase is initialised correctly
+M.course = M.course || {};
+M.course.coursebase = M.course.coursebase || new COURSEBASE();
+
+// Abstract functions that needs to be defined per format (course/format/somename/format.js)
+M.course.format = M.course.format || {};
+
+/**
+ * Swap section (should be defined in format.js if requred)
+ *
+ * @param {YUI} Y YUI3 instance
+ * @param {string} node1 node to swap to
+ * @param {string} node2 node to swap with
+ * @return {NodeList} section list
+ */
+M.course.format.swap_sections = M.course.format.swap_sections || function() {
+ return null;
+};
+
+/**
+ * Process sections after ajax response (should be defined in format.js)
+ * If some response is expected, we pass it over to format, as it knows better
+ * hot to process it.
+ *
+ * @param {YUI} Y YUI3 instance
+ * @param {NodeList} list of sections
+ * @param {array} response ajax response
+ * @param {string} sectionfrom first affected section
+ * @param {string} sectionto last affected section
+ * @return void
+ */
+M.course.format.process_sections = M.course.format.process_sections || function() {
+ return null;
+};
+
+/**
+* Get sections config for this format, for examples see function definition
+* in the formats.
+*
+* @return {object} section list configuration
+*/
+M.course.format.get_config = M.course.format.get_config || function() {
+ return {
+ container_node : null, // compulsory
+ container_class : null, // compulsory
+ section_wrapper_node : null, // optional
+ section_wrapper_class : null, // optional
+ section_node : null, // compulsory
+ section_class : null // compulsory
+ };
+};
+
+/**
+ * Get section list for this format (usually items inside container_node.container_class selector)
+ *
+ * @param {YUI} Y YUI3 instance
+ * @return {string} section selector
+ */
+M.course.format.get_section_selector = M.course.format.get_section_selector || function() {
+ var config = M.course.format.get_config();
+ if (config.section_node && config.section_class) {
+ return config.section_node + '.' + config.section_class;
+ }
+ Y.log('section_node and section_class are not defined in M.course.format.get_config', 'warn', 'moodle-course-coursebase');
+ return null;
+};
+
+/**
+ * Get section wraper for this format (only used in case when each
+ * container_node.container_class node is wrapped in some other element).
+ *
+ * @param {YUI} Y YUI3 instance
+ * @return {string} section wrapper selector or M.course.format.get_section_selector
+ * if section_wrapper_node and section_wrapper_class are not defined in the format config.
+ */
+M.course.format.get_section_wrapper = M.course.format.get_section_wrapper || function(Y) {
+ var config = M.course.format.get_config();
+ if (config.section_wrapper_node && config.section_wrapper_class) {
+ return config.section_wrapper_node + '.' + config.section_wrapper_class;
+ }
+ return M.course.format.get_section_selector(Y);
+};
+
+/**
+ * Get the tag of container node
+ *
+ * @return {string} tag of container node.
+ */
+M.course.format.get_containernode = M.course.format.get_containernode || function() {
+ var config = M.course.format.get_config();
+ if (config.container_node) {
+ return config.container_node;
+ } else {
+ Y.log('container_node is not defined in M.course.format.get_config', 'warn', 'moodle-course-coursebase');
+ }
+};
+
+/**
+ * Get the class of container node
+ *
+ * @return {string} class of the container node.
+ */
+M.course.format.get_containerclass = M.course.format.get_containerclass || function() {
+ var config = M.course.format.get_config();
+ if (config.container_class) {
+ return config.container_class;
+ } else {
+ Y.log('container_class is not defined in M.course.format.get_config', 'warn', 'moodle-course-coursebase');
+ }
+};
+
+/**
+ * Get the tag of draggable node (section wrapper if exists, otherwise section)
+ *
+ * @return {string} tag of the draggable node.
+ */
+M.course.format.get_sectionwrappernode = M.course.format.get_sectionwrappernode || function() {
+ var config = M.course.format.get_config();
+ if (config.section_wrapper_node) {
+ return config.section_wrapper_node;
+ } else {
+ return config.section_node;
+ }
+};
+
+/**
+ * Get the class of draggable node (section wrapper if exists, otherwise section)
+ *
+ * @return {string} class of the draggable node.
+ */
+M.course.format.get_sectionwrapperclass = M.course.format.get_sectionwrapperclass || function() {
+ var config = M.course.format.get_config();
+ if (config.section_wrapper_class) {
+ return config.section_wrapper_class;
+ } else {
+ return config.section_class;
+ }
+};
+
+/**
+ * Get the tag of section node
+ *
+ * @return {string} tag of section node.
+ */
+M.course.format.get_sectionnode = M.course.format.get_sectionnode || function() {
+ var config = M.course.format.get_config();
+ if (config.section_node) {
+ return config.section_node;
+ } else {
+ Y.log('section_node is not defined in M.course.format.get_config', 'warn', 'moodle-course-coursebase');
+ }
+};
+
+/**
+ * Get the class of section node
+ *
+ * @return {string} class of the section node.
+ */
+M.course.format.get_sectionclass = M.course.format.get_sectionclass || function() {
+ var config = M.course.format.get_config();
+ if (config.section_class) {
+ return config.section_class;
+ } else {
+ Y.log('section_class is not defined in M.course.format.get_config', 'warn', 'moodle-course-coursebase');
+ }
+};
--- /dev/null
+{
+ "moodle-course-coursebase": {
+ "requires": [
+ "base",
+ "node"
+ ]
+ }
+}
--- /dev/null
+{
+ "name": "moodle-course-dragdrop",
+ "builds": {
+ "moodle-course-dragdrop": {
+ "jsfiles": [
+ "dragdrop.js",
+ "section.js",
+ "resource.js"
+ ]
+ }
+ }
+}
--- /dev/null
+/**
+ * Drag and Drop for course sections and course modules.
+ *
+ * @module moodle-course-dragdrop
+ */
+
+var CSS = {
+ ACTIONAREA: '.actions',
+ ACTIVITY: 'activity',
+ ACTIVITYINSTANCE: 'activityinstance',
+ CONTENT: 'content',
+ COURSECONTENT: 'course-content',
+ EDITINGMOVE: 'editing_move',
+ ICONCLASS: 'iconsmall',
+ JUMPMENU: 'jumpmenu',
+ LEFT: 'left',
+ LIGHTBOX: 'lightbox',
+ MOVEDOWN: 'movedown',
+ MOVEUP: 'moveup',
+ PAGECONTENT: 'page-content',
+ RIGHT: 'right',
+ SECTION: 'section',
+ SECTIONADDMENUS: 'section_add_menus',
+ SECTIONHANDLE: 'section-handle',
+ SUMMARY: 'summary',
+ SECTIONDRAGGABLE: 'sectiondraggable'
+};
+
+M.course = M.course || {};
--- /dev/null
+/**
+ * Resource drag and drop.
+ *
+ * @class M.course.dragdrop.resource
+ * @constructor
+ * @extends M.core.dragdrop
+ */
+var DRAGRESOURCE = function() {
+ DRAGRESOURCE.superclass.constructor.apply(this, arguments);
+};
+Y.extend(DRAGRESOURCE, M.core.dragdrop, {
+ initializer: function() {
+ // Set group for parent class
+ this.groups = ['resource'];
+ this.samenodeclass = CSS.ACTIVITY;
+ this.parentnodeclass = CSS.SECTION;
+ this.resourcedraghandle = this.get_drag_handle(M.str.moodle.move, CSS.EDITINGMOVE, CSS.ICONCLASS, true);
+
+ // Go through all sections
+ var sectionlistselector = M.course.format.get_section_selector(Y);
+ if (sectionlistselector) {
+ sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + sectionlistselector;
+ this.setup_for_section(sectionlistselector);
+
+ // Initialise drag & drop for all resources/activities
+ var nodeselector = sectionlistselector.slice(CSS.COURSECONTENT.length + 2) + ' li.' + CSS.ACTIVITY;
+ var del = new Y.DD.Delegate({
+ container: '.' + CSS.COURSECONTENT,
+ nodes: nodeselector,
+ target: true,
+ handles: ['.' + CSS.EDITINGMOVE],
+ dragConfig: {groups: this.groups}
+ });
+ del.dd.plug(Y.Plugin.DDProxy, {
+ // Don't move the node at the end of the drag
+ moveOnEnd: false,
+ cloneNode: true
+ });
+ del.dd.plug(Y.Plugin.DDConstrained, {
+ // Keep it inside the .course-content
+ constrain: '#' + CSS.PAGECONTENT
+ });
+ del.dd.plug(Y.Plugin.DDWinScroll);
+
+ M.course.coursebase.register_module(this);
+ M.course.dragres = this;
+ }
+ },
+
+ /**
+ * Apply dragdrop features to the specified selector or node that refers to section(s)
+ *
+ * @method setup_for_section
+ * @param {String} baseselector The CSS selector or node to limit scope to
+ */
+ setup_for_section: function(baseselector) {
+ Y.Node.all(baseselector).each(function(sectionnode) {
+ var resources = sectionnode.one('.' + CSS.CONTENT + ' ul.' + CSS.SECTION);
+ // See if resources ul exists, if not create one
+ if (!resources) {
+ resources = Y.Node.create('<ul></ul>');
+ resources.addClass(CSS.SECTION);
+ sectionnode.one('.' + CSS.CONTENT + ' div.' + CSS.SUMMARY).insert(resources, 'after');
+ }
+ resources.setAttribute('data-draggroups', this.groups.join(' '));
+ // Define empty ul as droptarget, so that item could be moved to empty list
+ new Y.DD.Drop({
+ node: resources,
+ groups: this.groups,
+ padding: '20 0 20 0'
+ });
+
+ // Initialise each resource/activity in this section
+ this.setup_for_resource('#' + sectionnode.get('id') + ' li.' + CSS.ACTIVITY);
+ }, this);
+ },
+
+ /**
+ * Apply dragdrop features to the specified selector or node that refers to resource(s)
+ *
+ * @method setup_for_resource
+ * @param {String} baseselector The CSS selector or node to limit scope to
+ */
+ setup_for_resource: function(baseselector) {
+ Y.Node.all(baseselector).each(function(resourcesnode) {
+ // Replace move icons
+ var move = resourcesnode.one('a.' + CSS.EDITINGMOVE);
+ if (move) {
+ move.replace(this.resourcedraghandle.cloneNode(true));
+ }
+ }, this);
+ },
+
+ drag_start: function(e) {
+ // Get our drag object
+ var drag = e.target;
+ drag.get('dragNode').setContent(drag.get('node').get('innerHTML'));
+ drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline');
+ },
+
+ drag_dropmiss: function(e) {
+ // Missed the target, but we assume the user intended to drop it
+ // on the last last ghost node location, e.drag and e.drop should be
+ // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
+ this.drop_hit(e);
+ },
+
+ drop_hit: function(e) {
+ var drag = e.drag;
+ // Get a reference to our drag node
+ var dragnode = drag.get('node');
+ var dropnode = e.drop.get('node');
+
+ // Add spinner if it not there
+ var actionarea = dragnode.one(CSS.ACTIONAREA);
+ var spinner = M.util.add_spinner(Y, actionarea);
+
+ var params = {};
+
+ // Handle any variables which we must pass back through to
+ var pageparams = this.get('config').pageparams;
+ var varname;
+ for (varname in pageparams) {
+ params[varname] = pageparams[varname];
+ }
+
+ // Prepare request parameters
+ params.sesskey = M.cfg.sesskey;
+ params.courseId = this.get('courseid');
+ params['class'] = 'resource';
+ params.field = 'move';
+ params.id = Number(Y.Moodle.core_course.util.cm.getId(dragnode));
+ params.sectionId = Y.Moodle.core_course.util.section.getId(dropnode.ancestor(M.course.format.get_section_wrapper(Y), true));
+
+ if (dragnode.next()) {
+ params.beforeId = Number(Y.Moodle.core_course.util.cm.getId(dragnode.next()));
+ }
+
+ // Do AJAX request
+ var uri = M.cfg.wwwroot + this.get('ajaxurl');
+
+ Y.io(uri, {
+ method: 'POST',
+ data: params,
+ on: {
+ start: function() {
+ this.lock_drag_handle(drag, CSS.EDITINGMOVE);
+ spinner.show();
+ },
+ success: function(tid, response) {
+ var responsetext = Y.JSON.parse(response.responseText);
+ var params = {element: dragnode, visible: responsetext.visible};
+ M.course.coursebase.invoke_function('set_visibility_resource_ui', params);
+ this.unlock_drag_handle(drag, CSS.EDITINGMOVE);
+ window.setTimeout(function() {
+ spinner.hide();
+ }, 250);
+ },
+ failure: function(tid, response) {
+ this.ajax_failure(response);
+ this.unlock_drag_handle(drag, CSS.SECTIONHANDLE);
+ spinner.hide();
+ // TODO: revert nodes location
+ }
+ },
+ context:this
+ });
+ }
+}, {
+ NAME: 'course-dragdrop-resource',
+ ATTRS: {
+ courseid: {
+ value: null
+ },
+ ajaxurl: {
+ value: 0
+ },
+ config: {
+ value: 0
+ }
+ }
+});
+
+M.course = M.course || {};
+M.course.init_resource_dragdrop = function(params) {
+ new DRAGRESOURCE(params);
+};
--- /dev/null
+/**
+ * Section drag and drop.
+ *
+ * @class M.course.dragdrop.section
+ * @constructor
+ * @extends M.core.dragdrop
+ */
+var DRAGSECTION = function() {
+ DRAGSECTION.superclass.constructor.apply(this, arguments);
+};
+Y.extend(DRAGSECTION, M.core.dragdrop, {
+ sectionlistselector: null,
+
+ initializer: function() {
+ // Set group for parent class
+ this.groups = [ CSS.SECTIONDRAGGABLE ];
+ this.samenodeclass = M.course.format.get_sectionwrapperclass();
+ this.parentnodeclass = M.course.format.get_containerclass();
+
+ // Check if we are in single section mode
+ if (Y.Node.one('.' + CSS.JUMPMENU)) {
+ return false;
+ }
+ // Initialise sections dragging
+ this.sectionlistselector = M.course.format.get_section_wrapper(Y);
+ if (this.sectionlistselector) {
+ this.sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + this.sectionlistselector;
+
+ this.setup_for_section(this.sectionlistselector);
+
+ // Make each li element in the lists of sections draggable
+ var del = new Y.DD.Delegate({
+ container: '.' + CSS.COURSECONTENT,
+ nodes: '.' + CSS.SECTIONDRAGGABLE,
+ target: true,
+ handles: ['.' + CSS.LEFT],
+ dragConfig: {groups: this.groups}
+ });
+ del.dd.plug(Y.Plugin.DDProxy, {
+ // Don't move the node at the end of the drag
+ moveOnEnd: false
+ });
+ del.dd.plug(Y.Plugin.DDConstrained, {
+ // Keep it inside the .course-content
+ constrain: '#' + CSS.PAGECONTENT,
+ stickY: true
+ });
+ del.dd.plug(Y.Plugin.DDWinScroll);
+ }
+ },
+
+ /**
+ * Apply dragdrop features to the specified selector or node that refers to section(s)
+ *
+ * @method setup_for_section
+ * @param {String} baseselector The CSS selector or node to limit scope to
+ */
+ setup_for_section: function(baseselector) {
+ Y.Node.all(baseselector).each(function(sectionnode) {
+ // Determine the section ID
+ var sectionid = Y.Moodle.core_course.util.section.getId(sectionnode);
+
+ // We skip the top section as it is not draggable
+ if (sectionid > 0) {
+ // Remove move icons
+ var movedown = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEDOWN);
+ var moveup = sectionnode.one('.' + CSS.RIGHT + ' a.' + CSS.MOVEUP);
+
+ // Add dragger icon
+ var title = M.util.get_string('movesection', 'moodle', sectionid);
+ var cssleft = sectionnode.one('.' + CSS.LEFT);
+
+ if ((movedown || moveup) && cssleft) {
+ cssleft.setStyle('cursor', 'move');
+ cssleft.appendChild(this.get_drag_handle(title, CSS.SECTIONHANDLE, 'icon', true));
+
+ if (moveup) {
+ moveup.remove();
+ }
+ if (movedown) {
+ movedown.remove();
+ }
+
+ // This section can be moved - add the class to indicate this to Y.DD.
+ sectionnode.addClass(CSS.SECTIONDRAGGABLE);
+ }
+ }
+ }, this);
+ },
+
+ /*
+ * Drag-dropping related functions
+ */
+ drag_start: function(e) {
+ // Get our drag object
+ var drag = e.target;
+ // Creat a dummy structure of the outer elemnents for clean styles application
+ var containernode = Y.Node.create('<' + M.course.format.get_containernode() + '></' + M.course.format.get_containernode() + '>');
+ containernode.addClass(M.course.format.get_containerclass());
+ var sectionnode = Y.Node.create('<' + M.course.format.get_sectionwrappernode() + '></' + M.course.format.get_sectionwrappernode() + '>');
+ sectionnode.addClass( M.course.format.get_sectionwrapperclass());
+ sectionnode.setStyle('margin', 0);
+ sectionnode.setContent(drag.get('node').get('innerHTML'));
+ containernode.appendChild(sectionnode);
+ drag.get('dragNode').setContent(containernode);
+ drag.get('dragNode').addClass(CSS.COURSECONTENT);
+ },
+
+ drag_dropmiss: function(e) {
+ // Missed the target, but we assume the user intended to drop it
+ // on the last last ghost node location, e.drag and e.drop should be
+ // prepared by global_drag_dropmiss parent so simulate drop_hit(e).
+ this.drop_hit(e);
+ },
+
+ get_section_index: function(node) {
+ var sectionlistselector = '.' + CSS.COURSECONTENT + ' ' + M.course.format.get_section_selector(Y),
+ sectionList = Y.all(sectionlistselector),
+ nodeIndex = sectionList.indexOf(node),
+ zeroIndex = sectionList.indexOf(Y.one('#section-0'));
+
+ return (nodeIndex - zeroIndex);
+ },
+
+ drop_hit: function(e) {
+ var drag = e.drag;
+
+ // Get references to our nodes and their IDs.
+ var dragnode = drag.get('node'),
+ dragnodeid = Y.Moodle.core_course.util.section.getId(dragnode),
+ loopstart = dragnodeid,
+
+ dropnodeindex = this.get_section_index(dragnode),
+ loopend = dropnodeindex;
+
+ if (dragnodeid === dropnodeindex) {
+ Y.log("Skipping move - same location moving " + dragnodeid + " to " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
+ return;
+ }
+
+ Y.log("Moving from position " + dragnodeid + " to position " + dropnodeindex, 'debug', 'moodle-course-dragdrop');
+
+ if (loopstart > loopend) {
+ // If we're going up, we need to swap the loop order
+ // because loops can't go backwards.
+ loopstart = dropnodeindex;
+ loopend = dragnodeid;
+ }
+
+ // Get the list of nodes.
+ drag.get('dragNode').removeClass(CSS.COURSECONTENT);
+ var sectionlist = Y.Node.all(this.sectionlistselector);
+
+ // Add a lightbox if it's not there.
+ var lightbox = M.util.add_lightbox(Y, dragnode);
+
+ // Handle any variables which we must pass via AJAX.
+ var params = {},
+ pageparams = this.get('config').pageparams,
+ varname;
+
+ for (varname in pageparams) {
+ if (!pageparams.hasOwnProperty(varname)) {
+ continue;
+ }
+ params[varname] = pageparams[varname];
+ }
+
+ // Prepare request parameters
+ params.sesskey = M.cfg.sesskey;
+ params.courseId = this.get('courseid');
+ params['class'] = 'section';
+ params.field = 'move';
+ params.id = dragnodeid;
+ params.value = dropnodeindex;
+
+ // Perform the AJAX request.
+ var uri = M.cfg.wwwroot + this.get('ajaxurl');
+ Y.io(uri, {
+ method: 'POST',
+ data: params,
+ on: {
+ start: function() {
+ lightbox.show();
+ },
+ success: function(tid, response) {
+ // Update section titles, we can't simply swap them as
+ // they might have custom title
+ try {
+ var responsetext = Y.JSON.parse(response.responseText);
+ if (responsetext.error) {
+ new M.core.ajaxException(responsetext);
+ }
+ M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend);
+ } catch (e) {}
+
+ // Update all of the section IDs - first unset them, then set them
+ // to avoid duplicates in the DOM.
+ var index;
+
+ // Classic bubble sort algorithm is applied to the section
+ // nodes between original drag node location and the new one.
+ var swapped = false;
+ do {
+ swapped = false;
+ for (index = loopstart; index <= loopend; index++) {
+ if (Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) >
+ Y.Moodle.core_course.util.section.getId(sectionlist.item(index))) {
+ Y.log("Swapping " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index - 1)) +
+ " with " + Y.Moodle.core_course.util.section.getId(sectionlist.item(index)));
+ // Swap section id.
+ var sectionid = sectionlist.item(index - 1).get('id');
+ sectionlist.item(index - 1).set('id', sectionlist.item(index).get('id'));
+ sectionlist.item(index).set('id', sectionid);
+
+ // See what format needs to swap.
+ M.course.format.swap_sections(Y, index - 1, index);
+
+ // Update flag.
+ swapped = true;
+ }
+ }
+ loopend = loopend - 1;
+ } while (swapped);
+
+ window.setTimeout(function() {
+ lightbox.hide();
+ }, 250);
+ },
+
+ failure: function(tid, response) {
+ this.ajax_failure(response);
+ lightbox.hide();
+ }
+ },
+ context:this
+ });
+ }
+
+}, {
+ NAME: 'course-dragdrop-section',
+ ATTRS: {
+ courseid: {
+ value: null
+ },
+ ajaxurl: {
+ value: 0
+ },
+ config: {
+ value: 0
+ }
+ }
+});
+
+M.course = M.course || {};
+M.course.init_section_dragdrop = function(params) {
+ new DRAGSECTION(params);
+};
--- /dev/null
+{
+ "moodle-course-dragdrop": {
+ "requires": [
+ "base",
+ "node",
+ "io",
+ "dom",
+ "dd",
+ "dd-scroll",
+ "moodle-core-dragdrop",
+ "moodle-core-notification",
+ "moodle-course-coursebase",
+ "moodle-course-util"
+ ]
+ }
+}
--- /dev/null
+{
+ "name": "moodle-course-formatchooser",
+ "builds": {
+ "moodle-course-formatchooser": {
+ "jsfiles": [
+ "formatchooser.js"
+ ]
+ }
+ }
+}
--- /dev/null
+var FORMATCHOOSER = function() {
+ FORMATCHOOSER.superclass.constructor.apply(this, arguments);
+};
+
+Y.extend(FORMATCHOOSER, Y.Base, {
+ initializer : function(params) {
+ if (params && params.formid) {
+ var updatebut = Y.one('#'+params.formid+' #id_updatecourseformat');
+ var formatselect = Y.one('#'+params.formid+' #id_format');
+ if (updatebut && formatselect) {
+ updatebut.setStyle('display', 'none');
+ formatselect.on('change', function() {
+ updatebut.simulate('click');
+ });
+ }
+ }
+ }
+});
+
+M.course = M.course || {};
+M.course.init_formatchooser = function(params) {
+ return new FORMATCHOOSER(params);
+};
--- /dev/null
+{
+ "moodle-course-formatchooser": {
+ "requires": [
+ "base",
+ "node",
+ "node-event-simulate"
+ ]
+ }
+}
// The current section ID
sectionid : null,
- // The hidden element holding the jump param
- jumplink : null,
-
initializer : function() {
var dialogue = Y.one('.chooserdialoguebody');
var header = Y.one('.choosertitle');
e.preventDefault();
},
option_selected : function(thisoption) {
- // Add the sectionid to the URL
- this.jumplink.set('value', thisoption.get('value') + '§ion=' + this.sectionid);
+ // Add the sectionid to the URL.
+ this.hiddenRadioValue.setAttrs({
+ name: 'jump',
+ value: thisoption.get('value') + '§ion=' + this.sectionid
+ });
}
},
{
continue;
} else if ($ue->timestart and $ue->timeend) {
$period = get_string('periodstartend', 'enrol', array('start'=>userdate($ue->timestart), 'end'=>userdate($ue->timeend)));
- $periodoutside = ($ue->timestart && $ue->timeend && $now < $ue->timestart && $now > $ue->timeend);
+ $periodoutside = ($ue->timestart && $ue->timeend && ($now < $ue->timestart || $now > $ue->timeend));
} else if ($ue->timestart) {
$period = get_string('periodstart', 'enrol', userdate($ue->timestart));
$periodoutside = ($ue->timestart && $now < $ue->timestart);
* @param string|array $modules One or more modules to require
* @param string $function The JS function to call
* @param array $arguments An array of arguments to pass to the function
- * @param string $galleryversion The YUI gallery version of any modules required
+ * @param string $galleryversion Deprecated: The gallery version to use
* @param bool $ondomready If true the call is postponed until the DOM is finished loading
*/
- public function require_yui_module($modules, $function, array $arguments = null, $galleryversion = '2010.04.08-12-35', $ondomready = false) {
+ public function require_yui_module($modules, $function, array $arguments = null, $galleryversion = null, $ondomready = false) {
+ if ($galleryversion != null) {
+ debugging('The galleryversion parameter to yui_module has been deprecated since Moodle 2.3.', DEBUG_DEVELOPER);
+ }
+
$js = new stdClass;
$js->modules = (array)$modules;
$js->function = $function;
$js->arguments = $arguments;
- $js->galleryversion = $galleryversion;
$js->ondomready = $ondomready;
$this->jsyuimodules[] = $js;
}
*/
public function initialise_js(moodle_page $page) {
foreach ($this->jsyuimodules as $js) {
- $page->requires->yui_module($js->modules, $js->function, $js->arguments, $js->galleryversion, $js->ondomready);
+ $page->requires->yui_module($js->modules, $js->function, $js->arguments, null, $js->ondomready);
}
foreach ($this->jsinitcalls as $js) {
$page->requires->js_init_call($js->function, $js->extraarguments, $js->ondomready, $js->module);
* @return string
*/
public function user_roles_and_actions($userid, $roles, $assignableroles, $canassign, $pageurl) {
- $iconenroladd = $this->output->pix_url('t/enroladd');
$iconenrolremove = $this->output->pix_url('t/delete');
- // get list of roles
+
+
+ // Get list of roles.
$rolesoutput = '';
foreach ($roles as $roleid=>$role) {
if ($canassign and (is_siteadmin() or isset($assignableroles[$roleid])) and !$role['unchangeable']) {
}
}
if (!$hasallroles) {
- $url = new moodle_url($pageurl, array('action'=>'assign', 'user'=>$userid));
- $icon = html_writer::empty_tag('img', array('alt'=>get_string('assignroles', 'role'), 'src'=>$iconenroladd));
- $output = html_writer::tag('div', html_writer::link($url, $icon, array('class'=>'assignrolelink', 'title'=>get_string('assignroles', 'role'))), array('class'=>'addrole'));
+ $url = new moodle_url($pageurl, array('action' => 'assign', 'user' => $userid));
+ $roleicon = $this->output->pix_icon('i/assignroles', get_string('assignroles', 'role'));
+ $link = html_writer::link($url, $roleicon, array('class' => 'assignrolelink'));
+ $output = html_writer::tag('div', $link, array('class'=>'addrole'));
}
}
$output .= html_writer::tag('div', $rolesoutput, array('class'=>'roles'));
* @return string
*/
public function user_groups_and_actions($userid, $groups, $allgroups, $canmanagegroups, $pageurl) {
- $iconenroladd = $this->output->pix_url('t/enroladd');
$iconenrolremove = $this->output->pix_url('t/delete');
- $straddgroup = get_string('addgroup', 'group');
+
+ $groupicon = $this->output->pix_icon('i/group', get_string('addgroup', 'group'));
$groupoutput = '';
foreach($groups as $groupid=>$name) {
$groupoutput .= html_writer::tag('div', $name, array('class'=>'group', 'rel'=>$groupid));
}
}
- $groupoutput = html_writer::tag('div', $groupoutput, array('class'=>'groups'));
+ $output = '';
if ($canmanagegroups && (count($groups) < count($allgroups))) {
- $icon = html_writer::empty_tag('img', array('alt'=>$straddgroup, 'src'=>$iconenroladd));
$url = new moodle_url($pageurl, array('action'=>'addmember', 'user'=>$userid));
- $groupoutput .= html_writer::tag('div', html_writer::link($url, $icon), array('class'=>'addgroup'));
+ $output .= html_writer::tag('div', html_writer::link($url, $groupicon), array('class'=>'addgroup'));
}
- return $groupoutput;
+ $output = $output.html_writer::tag('div', $groupoutput, array('class'=>'groups'));
+ return $output;
}
/**
if (allroles) {
this.get(CONTAINER).addClass('hasAllRoles');
} else {
- if (!link) {
- var m = this.get(MANIPULATOR);
- link = Y.Node.create('<div class="addrole"></div>').append(
- Y.Node.create('<img alt="" />').setAttribute('src', M.util.image_url('t/enroladd', 'moodle'))
- );
- link.on('click', m.addRole, m, this);
- this.get(CONTAINER).one('.col_role').insert(link, 0);
- this.set(ASSIGNROLELINK, link);
- }
this.get(CONTAINER).removeClass('hasAllRoles');
}
},
AND ue.status = :uestatus
AND e.status = :estatus
AND e.courseid = :courseid
+ AND ue.timestart < :now1 AND (ue.timeend = 0 OR ue.timeend > :now2)
GROUP BY ue.userid";
$coursecontext = $this->context->get_course_context(true);
- $params = array_merge($uparams, array('estatus'=>ENROL_INSTANCE_ENABLED, 'uestatus'=>ENROL_USER_ACTIVE, 'courseid'=>$coursecontext->instanceid));
+ $time = time();
+ $params = array_merge($uparams, array('estatus' => ENROL_INSTANCE_ENABLED, 'uestatus' => ENROL_USER_ACTIVE,
+ 'courseid' => $coursecontext->instanceid, 'now1' => $time, 'now2' => $time));
$useractiveenrolments = $DB->get_records_sql($sql, $params);
$defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
$this->assertEquals($scale->id, $gradeitem->scaleid);
$this->assertEquals($scalestring, $cell->text, "Grade text matches scale");
- // Now change it to no grade.
+ // Now change it to no grade with gradebook feedback enabled.
+ $adminconfig = $assign->get_admin_config();
+ $gradebookplugin = $adminconfig->feedback_plugin_for_gradebook;
+ $gradebookplugin .= '_enabled';
+
$instance = $assign->get_instance();
$instance->grade = 0;
+ $instance->$gradebookplugin = 1;
$instance->instance = $instance->id;
$assign->update_instance($instance);
$this->assertEquals(GRADE_TYPE_TEXT, $gradeitem->gradetype);
$this->assertEquals(null, $gradeitem->scaleid);
$this->assertEquals(' - ', $cell->text, 'Grade text matches empty value of " - "');
+
+ // Now change it to no grade with gradebook feedback disabled.
+ $instance = $assign->get_instance();
+ $instance->grade = 0;
+ $instance->$gradebookplugin = 0;
+ $instance->instance = $instance->id;
+ $assign->update_instance($instance);
+
+ $gradeitem = grade_item::fetch($gradeitemparams);
+ $cell = $column->get_item_cell($gradeitem, array());
+
+ $this->assertEquals(GRADE_TYPE_NONE, $gradeitem->gradetype);
+ $this->assertEquals(null, $gradeitem->scaleid);
}
}
$config->lang = $lang;
if (!empty($_POST)) {
- if (install_ini_get_bool('magic_quotes_gpc')) {
- $_POST = array_map('stripslashes', $_POST);
- }
-
$config->stage = (int)$_POST['stage'];
if (isset($_POST['previous'])) {
$string['enablestats'] = 'Enable statistics';
$string['enabletgzbackups'] = 'Enable new backup format';
$string['enabletgzbackups_desc'] = 'If enabled, future backups will be created in a new compression format for .mbz files (internally stored as a .tar.gz file). This removes the 4GB backup size restriction and may improve performance. Restore supports both formats and the difference should be transparent to users.';
-$string['enabletgzbackups_nozlib'] = 'PHP extension ‘zlib’ is not available. The new backup format relies on this extension and will be disabled until zlib is installed and enabled.';
$string['enabletrusttext'] = 'Enable trusted content';
$string['enablewebservices'] = 'Enable web services';
$string['enablewsdocumentation'] = 'Web services documentation';
$string['experimentalsettings'] = 'Experimental settings';
$string['extendedusernamechars'] = 'Allow extended characters in usernames';
$string['extramemorylimit'] = 'Extra PHP memory limit';
-$string['fatalmagicquotesruntime'] = '<p>Serious configuration error detected, please notify server administrator.</p><p> To operate properly, Moodle requires that administrator changes PHP settings.</p><p><code>magic_quotes_runtime</code> must be set to <code>off</code>.</p><p>This setting is controlled by editing <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file on the server.</p>';
$string['fatalsessionautostart'] = '<p>Serious configuration error detected, please notify server administrator.</p><p> To operate properly, Moodle requires that administrator changes PHP settings.</p><p><code>session.auto_start</code> must be set to <code>off</code>.</p><p>This setting is controlled by editing <code>php.ini</code>, Apache/IIS <br />configuration or <code>.htaccess</code> file on the server.</p>';
$string['filecreated'] = 'New file created';
$string['filestoredin'] = 'Save file into folder :';
$string['purgecachesconfirm']= 'Moodle can cache themes, javascript, language strings, filtered text, rss feeds and many other pieces of calculated data. Purging these caches will delete that data from the server and force browsers to refetch data, so that you can be sure you are seeing the most up-to-date values produced by the current code. There is no danger in purging caches, but your site may appear slower for a while until the server and clients calculate new information and cache it.';
$string['purgecachesfinished']= 'All caches were purged.';
$string['requestcategoryselection'] = 'Enable category selection';
+$string['restorecourse'] = 'Restore course';
$string['restorernewroleid'] = 'Restorers\' role in courses';
$string['restorernewroleid_help'] = 'If the user does not already have the permission to manage the newly restored course, the user is automatically assigned this role and enrolled if necessary. Select "None" if you do not want restorers to be able to manage every restored course.';
$string['reverseproxy'] = 'Reverse proxy';
$string['upgrade197notice'] = '<p>Moodle 1.9.7 contains a number of security fixes to user passwords and backups to protect the user data on your site. As a result some of your settings and permissions relating to backups may have changed.<br />
See the <a href="http://docs.moodle.org/dev/Moodle_1.9.7_release_notes" target="_blank">Moodle 1.9.7 release notes</a> for full details.</p>';
$string['upgrade197noticesubject'] = 'Moodle 1.9.7 upgrade security notices';
-$string['upgrade197salt'] = 'To reduce the risk of password theft, you are strongly recommended to set a password salt.<br />See the <a href="{$a}" target="_blank">password salting documentation</a> for details.';
$string['upgradingdata'] = 'Upgrading data';
$string['upgradinglogs'] = 'Upgrading logs';
$string['upgradingversion'] = 'Upgrading to new version';
$string['xmlrpcrecommended'] = 'The xmlrpc extension is needed for hub communication, and useful for web services and Moodle networking';
$string['yuicomboloading'] = 'YUI combo loading';
$string['ziprequired'] = 'The Zip PHP extension is now required by Moodle, info-ZIP binaries or PclZip library are not used anymore.';
-$string['zlibenabled'] = 'zlib enabled';
$string['caching'] = 'Caching';
$string['errorrestorefrontpage'] = 'Restoring over front page is not allowed.';
$string['errorinvalidformat'] = 'Unknown backup format';
$string['errorinvalidformatinfo'] = 'The selected file is not a valid Moodle backup file and can\'t be restored.';
-$string['errortgznozlib'] = 'The selected file is in the new backup format and cannot be restored because the zlib PHP extension is not available on this system.';
$string['executionsuccess'] = 'The backup file was successfully created.';
$string['filename'] = 'Filename';
$string['filealiasesrestorefailures'] = 'Aliases restore failures';
$string['anymethodcourseset'] = 'Any of the selected courses is complete';
$string['anymethodmanual'] = 'Any of the selected roles awards the badge';
$string['anymethodprofile'] = 'Any of the selected profile fields has been completed';
+$string['archivebadge'] = 'Would you like to delete badge \'{$a}\', but keep existing issued badges?';
+$string['archiveconfirm'] = 'Delete and keep existing issued badges';
+$string['archivehelp'] = '<p>This option means that the badge will be marked as "retired" and will no longer appear in the list of badges. Users will no longer be able to earn this badge, however existing badge recipients will still be able to display this badge on their profile page and push it to their external backpacks.</p>
+<p>If you would like your users to retain access to the earned badges it is important to select this option instead of fully deleting badges.</p>';
$string['attachment'] = 'Attach badge to message';
$string['attachment_help'] = 'If checked, an issued badge file will be attached to the recepient\'s email for download. Email attachments must be enabled in site settings to use this option.';
$string['award'] = 'Award badge';
$string['defaultissuercontact_desc'] = 'An email address associated with the badge issuer.';
$string['defaultissuername'] = 'Default badge issuer name';
$string['defaultissuername_desc'] = 'Name of the issuing agent or authority.';
-$string['delbadge'] = 'Delete badge';
-$string['delconfirm'] = 'Are you sure that you want to delete badge \'{$a}\'?';
+$string['delbadge'] = 'Would you like to delete badge \'{$a}\' and remove all existing issued badges?';
+$string['delconfirm'] = 'Delete and remove existing issued badges';
+$string['deletehelp'] = '<p>Fully deleting a badge means that all its information and criteria records will be permanently removed. Users who have earned this badge will no longer be able to access it and display it on their profile pages.</p>
+<p>Note: Users who have earned this badge and have already pushed it to their external backpack, will still have this badge in their external backpack. However, they will not be able to access criteria and evidence pages linking back to this web site.</p>';
$string['delcritconfirm'] = 'Are you sure that you want to delete this criterion?';
$string['delparamconfirm'] = 'Are you sure that you want to delete this parameter?';
$string['description'] = 'Description';
$string['installation'] = 'Installation';
$string['langdownloaderror'] = 'Unfortunately the language "{$a}" could not be downloaded. The installation process will continue in English.';
$string['langdownloadok'] = 'The language "{$a}" was installed successfully. The installation process will continue in this language.';
-$string['magicquotesruntime'] = 'Magic quotes run time';
-$string['magicquotesruntimeerror'] = 'This should be off';
-$string['magicquotesruntimehelp'] = '<p>Magic quotes runtime should be turned off for Moodle to function properly.</p>
-
-<p>Normally it is off by default ... see the setting <b>magic_quotes_runtime</b> in your php.ini file.</p>
-
-<p>If you don\'t have access to your php.ini, you might be able to place the following line in a file
- called .htaccess within your Moodle directory:</p>
- <blockquote><div>php_value magic_quotes_runtime Off</div></blockquote>';
$string['memorylimit'] = 'Memory limit';
$string['memorylimiterror'] = 'The PHP memory limit is set quite low ... you may run into problems later.';
$string['memorylimithelp'] = '<p>The PHP memory limit for your server is currently set to {$a}.</p>
rebuild_course_cache(0, true);
}
- add_to_config_log($name, $oldvalue, $value, $this->plugin);
+ $this->add_to_config_log($name, $oldvalue, $value);
return true; // BC only
}
+ /**
+ * Log config changes if necessary.
+ * @param string $name
+ * @param string $oldvalue
+ * @param string $value
+ */
+ protected function add_to_config_log($name, $oldvalue, $value) {
+ add_to_config_log($name, $oldvalue, $value, $this->plugin);
+ }
+
/**
* Returns current value of this setting
* @return mixed array or string depending on instance, NULL means not set yet
parent::__construct($name, $visiblename, $description, $defaultsetting, PARAM_RAW, 30);
}
+ /**
+ * Log config changes if necessary.
+ * @param string $name
+ * @param string $oldvalue
+ * @param string $value
+ */
+ protected function add_to_config_log($name, $oldvalue, $value) {
+ if ($value !== '') {
+ $value = '********';
+ }
+ if ($oldvalue !== '' and $oldvalue !== null) {
+ $oldvalue = '********';
+ }
+ parent::add_to_config_log($name, $oldvalue, $value);
+ }
+
/**
* Returns XHTML for the field
* Writes Javascript into the HTML below right before the last div
}
/**
- * Marks the badge as archived.
- * For reporting and historical purposed we cannot completely delete badges.
- * We will just change their status to BADGE_STATUS_ARCHIVED.
+ * Fully deletes the badge or marks it as archived.
+ *
+ * @param $archive bool Achive a badge without actual deleting of any data.
*/
- public function delete() {
- $this->status = BADGE_STATUS_ARCHIVED;
- $this->save();
+ public function delete($archive = true) {
+ global $DB;
+
+ if ($archive) {
+ $this->status = BADGE_STATUS_ARCHIVED;
+ $this->save();
+ return;
+ }
+
+ $fs = get_file_storage();
+
+ // Remove all issued badge image files and badge awards.
+ // Cannot bulk remove area files here because they are issued in user context.
+ $awards = $this->get_awards();
+ foreach ($awards as $award) {
+ $usercontext = context_user::instance($award->userid);
+ $fs->delete_area_files($usercontext->id, 'badges', 'userbadge', $this->id);
+ }
+ $DB->delete_records('badge_issued', array('badgeid' => $this->id));
+
+ // Remove all badge criteria.
+ $criteria = $this->get_criteria();
+ foreach ($criteria as $criterion) {
+ $criterion->delete();
+ }
+
+ // Delete badge images.
+ $badgecontext = $this->get_context();
+ $fs->delete_area_files($badgecontext->id, 'badges', 'badgeimage', $this->id);
+
+ // Finally, remove badge itself.
+ $DB->delete_records('badge', array('id' => $this->id));
}
}
*/
public function set_value($value) {
+ if (!$this->running_javascript()) {
+ $this->field->check();
+ return;
+ }
+
if (!empty($value) && !$this->field->isChecked()) {
// Check it if it should be checked and it is not.
$this->field->click();
// Wrapped in a try & catch as we can fall into race conditions
// and the element may not be there.
try {
+
+ // Wait for all the possible AJAX requests that have been
+ // already triggered by selectOption() to be finished.
+ $this->session->wait(behat_base::TIMEOUT * 1000, behat_base::PAGE_READY_JS);
+
current($optionnodes)->click();
} catch (Exception $e) {
// We continue and return as this means that the element is not there or it is not the same.
}
} else {
+
+ // Wait for all the possible AJAX requests that have been
+ // already triggered by selectOption() to be finished.
+ $this->session->wait(behat_base::TIMEOUT * 1000, behat_base::PAGE_READY_JS);
+
// Wrapped in a try & catch as we can fall into race conditions
// and the element may not be there.
try {
return;
}
+ // Wait for all the possible AJAX requests that have been
+ // already triggered by selectOption() to be finished.
+ $this->session->wait(behat_base::TIMEOUT * 1000, behat_base::PAGE_READY_JS);
+
// Wrapped in a try & catch as we can fall into race conditions
// and the element may not be there.
try {
opcache_invalidate($file, true);
}
}
+
+ /**
+ * Return true if subsystemname is core subsystem.
+ *
+ * @param string $subsystemname name of the subsystem.
+ * @return bool true if core subsystem.
+ */
+ public static function is_core_subsystem($subsystemname) {
+ return isset(self::$subsystems[$subsystemname]);
+ }
}
*
* Both events could be triggered in a row, first the uploaded, then the submitted.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type array pathnamehashes uploaded files path name hashes.
+ * @type string content string.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* Class for event to be triggered when a new blog entry is associated with a context.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string associatetype type of blog association, course/coursemodule.
+ * @type int blogid id of blog.
+ * @type int associateid id of associate.
+ * @type string subject blog subject.
+ * }
+ *
* @package core
* @copyright 2013 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
--- /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/>.
+
+/**
+ * blog comment created event.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * blog comment created event.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_comment_created extends \core\event\comment_created {
+ /**
+ * Get URL related to the action.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/blog/index.php', array('entryid' => $this->other['itemid']));
+ }
+
+ /**
+ * Returns description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'User with id ' . $this->userid . ' added comment for blog with id ' . $this->other['itemid'];
+ }
+}
--- /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/>.
+
+/**
+ * blog comment deleted event.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * blog comment deleted event.
+ *
+ * @package core
+ * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class blog_comment_deleted extends \core\event\comment_deleted {
+ /**
+ * Get URL related to the action.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return new \moodle_url('/blog/index.php', array('entryid' => $this->other['itemid']));
+ }
+
+ /**
+ * Returns description of what happened.
+ *
+ * @return string
+ */
+ public function get_description() {
+ return 'User with id ' . $this->userid . ' deleted comment for blog with id ' . $this->other['itemid'];
+ }
+}
*
* Class for event to be triggered when blog entries are viewed.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int courseid id of associated course.
+ * }
+ *
* @package core
* @copyright 2013 onwards Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* This class has to be extended by any event which is triggred while creating new comment.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int itemid id of item for which comment is added.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @return string
*/
public function get_description() {
- return 'User with id '. $this->userid . ' added comment for ' . $this->component . ' with instance id ' .
+ return 'User with id ' . $this->userid . ' added comment for ' . $this->component . ' with instance id ' .
$this->contextinstanceid;
}
+ /**
+ * Get URL related to the action.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return $this->context->get_url();
+ }
+
/**
* Custom validation.
*
*
* This class has to be extended by any event which is triggred while deleting comment.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int itemid id of item for which comment is deleted.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @return string
*/
public function get_description() {
- return 'User with id '. $this->userid . ' deleted comment for ' . $this->component . ' with instance id ' .
+ return 'User with id ' . $this->userid . ' deleted comment for ' . $this->component . ' with instance id ' .
$this->contextinstanceid;
}
+ /**
+ * Get URL related to the action.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return $this->context->get_url();
+ }
+
/**
* Custom validation.
*
return 'User with id '. $this->userid . ' viewed comments for ' . $this->component . ' with instance id ' .
$this->objectid;
}
+
+ /**
+ * Get URL related to the action.
+ *
+ * @return \moodle_url
+ */
+ public function get_url() {
+ return $this->context->get_url();
+ }
}
* $event->trigger();
* where \report_participation\event\content_viewed extends \core\event\content_viewed
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string content viewed content identifier.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
defined('MOODLE_INTERNAL') || die();
/**
- * category deleted event.
+ * Category deleted event.
+ *
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string name category name.
+ * }
*
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
/**
* Course content_deleted event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type array options list of options which were skipped while deleting course content.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Course created event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string shortname shortname of course.
+ * @type string fullname fullname of course.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Course deleted event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string shortname shortname of course.
+ * @type string fullname fullname of course.
+ * @type string idnumber id number of course.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Event to be triggered when a new course module is created.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string modulename name of module created.
+ * @type string name title of module.
+ * @type string instanceid id of module instance.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*
* Class for event to be triggered when a course module is deleted.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string modulename name of module deleted.
+ * @type string instanceid id of module instance.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
*
* Class for event to be triggered when a course module is updated.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string modulename name of module updated.
+ * @type string name title of module.
+ * @type string instanceid id of module instance.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
/**
* core course reset ended event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type array reset_options all reset options settings including courseid.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core course reset started event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type array reset_options all reset options settings including courseid.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Course restored event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string type restore type, activity, course or section.
+ * @type int target where restored (new/existing/current/adding/deleting)
+ * @type int mode execution mode
+ * @type string opertaion restore
+ * @type boolean samesite true is restored to same site.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Course section updated.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int sectionnum section number.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Course updated event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string shortname shortname of course.
+ * @type string fullname fullname of course.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core_group member added event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string component name of component
+ * @type int itemid id of item.
+ * }
+ *
* @package core_group
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* Class for event to be triggered when a note is created.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string publishstate publish state.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* Class for event to be triggered when a note is deleted.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string publishstate publish state
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* Class for event to be triggered when a note is updated.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string publishstate publish state.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*
* Class for event to be triggered when a note is viewed.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string content hard-coded to notes.
+ * }
+ *
* @package core
* @copyright 2013 Ankit Agarwal
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Role assigned event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int id role assigned id.
+ * @type string component name of component.
+ * @type int itemid id of item.
+ * }
+ *
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Role assigned event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string shortname shortname of role.
+ * @type string description role description.
+ * @type string archetype role type.
+ * }
+ *
* @package core_event
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Role unassigned event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int id role assigned id.
+ * @type string component name of component.
+ * @type int itemid id of item.
+ * }
+ *
* @package core
* @copyright 2013 Petr Skoda {@link http://skodak.org}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Event when user profile is deleted.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string username name of user.
+ * @type string email user email.
+ * @type string idnumber user idnumber.
+ * @type string picture user picture.
+ * @type int mnethostid mnet host id.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Event when user is enrolled in a course.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string enrol name of enrolment instance.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* User enrolment deleted event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string enrol name of enrolment instance.
+ * @type array userenrolment user_enrolment record.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Event when user enrolment is updated.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string enrol name of enrolment instance.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Defines the user list viewed event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int courseid id of course.
+ * @type string courseshortname short name of course.
+ * @type string coursefullname full name of course.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* User login event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string username name of user.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* User loggedinas event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string originalusername original username.
+ * @type string loggedinasusername username of logged in as user.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Event when user logout.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string sessionid session id.
+ * }
+ *
* @package core
* @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* Defines the user profile viewed event.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type int courseid id of course.
+ * @type string courseshortname short name of course.
+ * @type string coursefullname fullname of course.
+ * }
+ *
* @package core
* @copyright 2013 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core webservice function_called event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string function name of the function.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core web service login_failed event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string method authentication method.
+ * @type string reason failure reason.
+ * @type string tokenid id of token.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core webservice service created event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type string sessionid session id.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
/**
* core webservice token_created event class.
*
+ * @property-read array $other {
+ * Extra information about event.
+ *
+ * @type bool auto automatically created.
+ * }
+ *
* @package core
* @copyright 2013 Frédéric Massart
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
// zlib.output_compression is preferred over ob_gzhandler()
if (!empty($_SERVER['HTTP_USER_AGENT']) and strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 6') !== false) {
- @ini_set('zlib.output_compression', 'Off');
+ ini_set('zlib.output_compression', 'Off');
if (function_exists('apache_setenv')) {
- @apache_setenv('no-gzip', 1);
+ apache_setenv('no-gzip', 1);
}
return false;
}
- @ini_set('output_handler', '');
+ ini_set('output_handler', '');
/*
* docs clearly say 'on' means enable and number means size of buffer,
* 1 probably sets chunk size to 4096. our CSS and JS scripts are much bigger,
* so let's try some bigger sizes.
*/
- @ini_set('zlib.output_compression', 65536);
+ ini_set('zlib.output_compression', 65536);
return true;
}
return $this->has_manage_capability();
}
+ /**
+ * Returns true if the user is able to restore a course into this category as a new course.
+ * @return bool
+ */
+ public function can_restore_courses_into() {
+ return has_capability('moodle/course:create', $this->get_context());
+ }
+
/**
* Resorts the sub categories of this category by the given field.
*
// Generate new password emails for users - ppl expect these generated asap
if ($DB->count_records('user_preferences', array('name'=>'create_password', 'value'=>'1'))) {
mtrace('Creating passwords for new users...');
- $newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email, u.firstname,
- u.lastname, u.username, u.lang,
+ $usernamefields = get_all_user_name_fields(true, 'u');
+ $newusers = $DB->get_recordset_sql("SELECT u.id as id, u.email,
+ $usernamefields, u.username, u.lang,
p.id as prefid
FROM {user} u
JOIN {user_preferences} p ON u.id=p.userid
upgrade_main_savepoint(true, 2013111800.01);
}
+ if ($oldversion < 2013122400.01) {
+ // Purge stored passwords from config_log table, ideally this should be in each plugin
+ // but that would complicate backporting...
+ $items = array(
+ 'core/cronremotepassword', 'core/proxypassword', 'core/smtppass', 'core/jabberpassword',
+ 'enrol_database/dbpass', 'enrol_ldap/bind_pw', 'url/secretphrase');
+ foreach ($items as $item) {
+ list($plugin, $name) = explode('/', $item);
+ if ($plugin === 'core') {
+ $sql = "UPDATE {config_log}
+ SET value = :value
+ WHERE name = :name AND plugin IS NULL AND value <> ''";
+ $params = array('value'=>'********', 'name'=>$name);
+ $DB->execute($sql, $params);
+
+ $sql = "UPDATE {config_log}
+ SET oldvalue = :value
+ WHERE name = :name AND plugin IS NULL AND oldvalue <> ''";
+ $params = array('value'=>'********', 'name'=>$name);
+ $DB->execute($sql, $params);
+
+ } else {
+ $sql = "UPDATE {config_log}
+ SET value = :value
+ WHERE name = :name AND plugin = :plugin AND value <> ''";
+ $params = array('value'=>'********', 'name'=>$name, 'plugin'=>$plugin);
+ $DB->execute($sql, $params);
+
+ $sql = "UPDATE {config_log}
+ SET oldvalue = :value
+ WHERE name = :name AND plugin = :plugin AND oldvalue <> ''";
+ $params = array('value'=>'********', 'name'=>$name, 'plugin'=>$plugin);
+ $DB->execute($sql, $params);
+ }
+ }
+ // Main savepoint reached.
+ upgrade_main_savepoint(true, 2013122400.01);
+ }
+
return true;
}
defined('MOODLE_INTERNAL') || die();
+/**
+ * Checks whether the password compatibility library will work with the current
+ * version of PHP. This cannot be done using PHP version numbers since the fix
+ * has been backported to earlier versions in some distributions.
+ *
+ * See https://github.com/ircmaxell/password_compat/issues/10 for more details.
+ *
+ * @deprecated since 2.7 PHP 5.4.x should be always compatible.
+ *
+ * @return bool always returns false
+ */
+function password_compat_not_supported() {
+ debugging('Do not use password_compat_not_supported() - bcrypt is now always available', DEBUG_DEVELOPER);
+ return false;
+}
+
/**
* Factory method that was returning moodle_session object.
*
array $options = null) {
global $USER;
+ if (!isloggedin() or isguestuser()) {
+ // Must be a real user to manage any files.
+ return;
+ }
+ if (!isset($options['maxfiles']) or $options['maxfiles'] == 0) {
+ // No files allowed - easy, do not load anything.
+ return;
+ }
+
// Add parameters for filemanager
$params['managefiles'] = array('usercontext' => context_user::instance($USER->id)->id);
foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types') as $key) {
header('Content-Disposition: attachment; filename="'.$filename.'"');
if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
- header('Cache-Control: private, max-age=10');
+ header('Cache-Control: private, max-age=10, no-transform');
header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
header('Pragma: ');
} else { //normal http - prevent caching at all cost
- header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
+ header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0, no-transform');
header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
header('Pragma: no-cache');
}
$private = ' private,';
}
$nobyteserving = false;
- header('Cache-Control:'.$private.' max-age='.$lifetime);
+ header('Cache-Control:'.$private.' max-age='.$lifetime.', no-transform');
header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
header('Pragma: ');
} else { // Do not cache files in proxies and browsers
$nobyteserving = true;
if (strpos($CFG->wwwroot, 'https://') === 0) { //https sites - watch out for IE! KB812935 and KB316431
- header('Cache-Control: private, max-age=10');
+ header('Cache-Control: private, max-age=10, no-transform');
header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
header('Pragma: ');
} else { //normal http - prevent caching at all cost
- header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0');
+ header('Cache-Control: private, must-revalidate, pre-check=0, post-check=0, max-age=0, no-transform');
header('Expires: '. gmdate('D, d M Y H:i:s', 0) .' GMT');
header('Pragma: no-cache');
}