Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f810374a0e | |||
| 6c73be6e8e | |||
| 5a7599385f | |||
| eae457d10d | |||
| 56eb910aed | |||
| 11dcef291d | |||
| 42cbafd610 | |||
| fb1752711e | |||
| 99eb359503 | |||
| 6f344ff877 | |||
| 68c20d41fe | |||
| 4272fc3f28 | |||
| 1bd5dfe090 | |||
| f8d0e86350 | |||
| e092c75d15 | |||
| 90b3f5fc26 | |||
| c77bef3ad7 | |||
| 260eef0a72 | |||
| af0fe95d84 | |||
| ee0c928f10 | |||
| d1796d1f0e | |||
| ac2acd0072 | |||
| 155abc6945 | |||
| cf0b182dee | |||
| f863084cc9 | |||
| 2ddad8ce7a | |||
| 8d45a9f2a2 | |||
| 4b0a34f08a | |||
| 3a7f291d38 | |||
| bbfc6312a8 | |||
| 983921ecff | |||
| d7a1ef5dfa | |||
| 0cb2fd1a7f | |||
| 4ac4b93064 | |||
| 26c5ffd356 |
+32
-43
@@ -49,26 +49,11 @@ if ($action == 'newon') {
|
||||
|
||||
admin_externalpage_setup($pagename);
|
||||
|
||||
$sesskeyurl = $CFG->wwwroot.'/'.$CFG->admin.'/repository.php?sesskey=' . sesskey();
|
||||
$baseurl = $CFG->wwwroot.'/'.$CFG->admin.'/repository.php';
|
||||
|
||||
$configstr = get_string('manage', 'repository');
|
||||
// The URL used for redirection, and that all edit related URLs will be based off.
|
||||
$baseurl = new moodle_url('/admin/repository.php');
|
||||
|
||||
$return = true;
|
||||
|
||||
if (!empty($action)) {
|
||||
require_sesskey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that generates a moodle_url object
|
||||
* relevant to the repository
|
||||
*/
|
||||
function repository_action_url($repository) {
|
||||
global $baseurl;
|
||||
return new moodle_url($baseurl, array('sesskey'=>sesskey(), 'repos'=>$repository));
|
||||
}
|
||||
|
||||
if (($action == 'edit') || ($action == 'new')) {
|
||||
$pluginname = '';
|
||||
if ($action == 'edit') {
|
||||
@@ -182,16 +167,12 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
}
|
||||
}
|
||||
} else if ($action == 'show') {
|
||||
if (!confirm_sesskey()) {
|
||||
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
|
||||
}
|
||||
require_sesskey();
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('repository');
|
||||
$class::enable_plugin($repository, 1);
|
||||
$return = true;
|
||||
} else if ($action == 'hide') {
|
||||
if (!confirm_sesskey()) {
|
||||
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
|
||||
}
|
||||
require_sesskey();
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('repository');
|
||||
$class::enable_plugin($repository, 0);
|
||||
$return = true;
|
||||
@@ -199,9 +180,7 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
$repositorytype = repository::get_type_by_typename($repository);
|
||||
if ($sure) {
|
||||
$PAGE->set_pagetype('admin-repository-' . $repository);
|
||||
if (!confirm_sesskey()) {
|
||||
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
|
||||
}
|
||||
require_sesskey();
|
||||
|
||||
if ($repositorytype->delete($downloadcontents)) {
|
||||
// Include this information into config changes table.
|
||||
@@ -220,20 +199,15 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
$output = $OUTPUT->box_start('generalbox', 'notice');
|
||||
$output .= html_writer::tag('p', $message);
|
||||
|
||||
$removeurl = new moodle_url($sesskeyurl);
|
||||
$removeurl->params(array(
|
||||
$removeurl = new moodle_url($baseurl, [
|
||||
'action' =>'delete',
|
||||
'repos' => $repository,
|
||||
'sure' => 'yes',
|
||||
));
|
||||
]);
|
||||
|
||||
$removeanddownloadurl = new moodle_url($sesskeyurl);
|
||||
$removeanddownloadurl->params(array(
|
||||
'action' =>'delete',
|
||||
'repos'=> $repository,
|
||||
'sure' => 'yes',
|
||||
$removeanddownloadurl = new moodle_url($removeurl, [
|
||||
'downloadcontents' => 1,
|
||||
));
|
||||
]);
|
||||
|
||||
$output .= $OUTPUT->single_button($removeurl, get_string('continueuninstall', 'repository'));
|
||||
$output .= $OUTPUT->single_button($removeanddownloadurl, get_string('continueuninstallanddownload', 'repository'));
|
||||
@@ -245,9 +219,11 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
$return = false;
|
||||
}
|
||||
} else if ($action == 'moveup') {
|
||||
require_sesskey();
|
||||
$repositorytype = repository::get_type_by_typename($repository);
|
||||
$repositorytype->move_order('up');
|
||||
} else if ($action == 'movedown') {
|
||||
require_sesskey();
|
||||
$repositorytype = repository::get_type_by_typename($repository);
|
||||
$repositorytype->move_order('down');
|
||||
} else {
|
||||
@@ -339,8 +315,7 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
$userinstancenumbertext = "";
|
||||
}
|
||||
|
||||
$settings .= '<a href="' . $sesskeyurl . '&action=edit&repos=' . $typename . '">' . $settingsstr .'</a>';
|
||||
|
||||
$settings = html_writer::link(new moodle_url($baseurl, ['action' => 'edit', 'repos' => $typename]), $settingsstr);
|
||||
$settings .= $OUTPUT->container_start('mdl-left');
|
||||
$settings .= '<br/>';
|
||||
$settings .= $admininstancenumbertext;
|
||||
@@ -357,22 +332,34 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
$currentaction = 'hide';
|
||||
}
|
||||
|
||||
$select = new single_select(repository_action_url($typename, 'repos'), 'action', $actionchoicesforexisting, $currentaction, null, 'applyto' . basename($typename));
|
||||
// Active toggle.
|
||||
$selectaction = new moodle_url($baseurl, ['sesskey' => sesskey(), 'repos' => $typename]);
|
||||
$select = new single_select($selectaction, 'action', $actionchoicesforexisting, $currentaction, null,
|
||||
'applyto' . basename($typename));
|
||||
$select->set_label(get_string('action'), array('class' => 'accesshide'));
|
||||
|
||||
// Display up/down link
|
||||
$updown = '';
|
||||
$spacer = $OUTPUT->spacer(array('height'=>15, 'width'=>15)); // should be done with CSS instead
|
||||
|
||||
if ($updowncount > 1) {
|
||||
$updown .= "<a href=\"$sesskeyurl&action=moveup&repos=".$typename."\">";
|
||||
$updown .= $OUTPUT->pix_icon('t/up', get_string('moveup')) . "</a> ";
|
||||
$moveupaction = new moodle_url($baseurl, [
|
||||
'sesskey' => sesskey(),
|
||||
'action' => 'moveup',
|
||||
'repos' => $typename,
|
||||
]);
|
||||
$updown .= html_writer::link($moveupaction, $OUTPUT->pix_icon('t/up', get_string('moveup'))) . ' ';
|
||||
}
|
||||
else {
|
||||
$updown .= $spacer;
|
||||
}
|
||||
if ($updowncount < $totalrepositorytypes) {
|
||||
$updown .= "<a href=\"$sesskeyurl&action=movedown&repos=".$typename."\">";
|
||||
$updown .= $OUTPUT->pix_icon('t/down', get_string('movedown')) . "</a> ";
|
||||
$movedownaction = new moodle_url($baseurl, [
|
||||
'sesskey' => sesskey(),
|
||||
'action' => 'movedown',
|
||||
'repos' => $typename,
|
||||
]);
|
||||
$updown .= html_writer::link($movedownaction, $OUTPUT->pix_icon('t/down', get_string('movedown'))) . ' ';
|
||||
}
|
||||
else {
|
||||
$updown .= $spacer;
|
||||
@@ -400,7 +387,9 @@ if (($action == 'edit') || ($action == 'new')) {
|
||||
foreach ($plugins as $plugin => $dir) {
|
||||
// Check that it has not already been listed
|
||||
if (!in_array($plugin, $alreadyplugins)) {
|
||||
$select = new single_select(repository_action_url($plugin, 'repos'), 'action', $actionchoicesfornew, 'delete', null, 'applyto' . basename($plugin));
|
||||
$selectaction = new moodle_url($baseurl, ['sesskey' => sesskey(), 'repos' => $plugin]);
|
||||
$select = new single_select($selectaction, 'action', $actionchoicesfornew, 'delete', null,
|
||||
'applyto' . basename($plugin));
|
||||
$select->set_label(get_string('action'), array('class' => 'accesshide'));
|
||||
$uninstall = '';
|
||||
if ($uninstallurl = core_plugin_manager::instance()->get_uninstall_url('repository_' . $plugin, 'manage')) {
|
||||
|
||||
@@ -18,8 +18,6 @@ require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
require_sesskey();
|
||||
|
||||
// id of repository
|
||||
$edit = optional_param('edit', 0, PARAM_INT);
|
||||
$new = optional_param('new', '', PARAM_PLUGIN);
|
||||
@@ -43,12 +41,8 @@ if ($edit){
|
||||
|
||||
admin_externalpage_setup($pagename, '', null, new moodle_url('/admin/repositoryinstance.php'));
|
||||
|
||||
$baseurl = new moodle_url("/$CFG->admin/repositoryinstance.php", array('sesskey'=>sesskey()));
|
||||
|
||||
$parenturl = new moodle_url("/$CFG->admin/repository.php", array(
|
||||
'sesskey'=>sesskey(),
|
||||
'action'=>'edit',
|
||||
));
|
||||
// The URL used for redirection, and that all edit related URLs will be based off.
|
||||
$parenturl = new moodle_url('/admin/repository.php', ['action' => 'edit']);
|
||||
|
||||
if ($new) {
|
||||
$parenturl->param('repos', $new);
|
||||
@@ -116,6 +110,7 @@ if (!empty($edit) || !empty($new)) {
|
||||
$return = false;
|
||||
}
|
||||
} else if (!empty($hide)) {
|
||||
require_sesskey();
|
||||
$instance = repository::get_type_by_typename($hide);
|
||||
$instance->hide();
|
||||
core_plugin_manager::reset_caches();
|
||||
@@ -129,6 +124,7 @@ if (!empty($edit) || !empty($new)) {
|
||||
throw new repository_exception('nopermissiontoaccess', 'repository');
|
||||
}
|
||||
if ($sure) {
|
||||
require_sesskey();
|
||||
if ($instance->delete($downloadcontents)) {
|
||||
$deletedstr = get_string('instancedeleted', 'repository');
|
||||
core_plugin_manager::reset_caches();
|
||||
@@ -141,14 +137,17 @@ if (!empty($edit) || !empty($new)) {
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->box_start('generalbox', 'notice');
|
||||
$continueurl = new moodle_url($baseurl, array(
|
||||
|
||||
$continueurl = new moodle_url($PAGE->url, [
|
||||
'type' => $type,
|
||||
'delete' => $delete,
|
||||
'sure' => 'yes',
|
||||
));
|
||||
]);
|
||||
|
||||
$continueanddownloadurl = new moodle_url($continueurl, array(
|
||||
'downloadcontents' => 1
|
||||
));
|
||||
|
||||
$message = get_string('confirmdelete', 'repository', $instance->name);
|
||||
echo html_writer::tag('p', $message);
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
@tool_behat
|
||||
Feature: Confirm that we can open multiple browser tabs
|
||||
In order to use multiple browser tabs
|
||||
As a test writer
|
||||
I need the relevant Behat steps to work
|
||||
|
||||
@javascript @_switch_window
|
||||
Scenario: Open multiple browser tabs
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
| Course 2 | C2 |
|
||||
| Course 3 | C3 |
|
||||
And I am on the "C1" "Course" page logged in as "admin"
|
||||
|
||||
# Open a new tab on the same page.
|
||||
When I open a tab named "CourseViewer1" on the current page
|
||||
And I should see "Course 1" in the "h1" "css_element"
|
||||
And I am on the "C2" "Course" page
|
||||
|
||||
# Open new tab for specified page with identifier.
|
||||
And I open a tab named "CourseViewer2" on the "C3" "Course" page
|
||||
|
||||
# And for a specified page without identifier.
|
||||
And I open a tab named "CourseViewer4" on the "My courses" page
|
||||
|
||||
# Switch between all the tabs and confirm their different contents.
|
||||
Then I should see "You're not enrolled in any course"
|
||||
And I switch to "CourseViewer2" tab
|
||||
And I should see "Course 3" in the "h1" "css_element"
|
||||
And I switch to "CourseViewer1" tab
|
||||
And I should see "Course 2" in the "h1" "css_element"
|
||||
And I switch to the main tab
|
||||
And I should see "Course 1" in the "h1" "css_element"
|
||||
@@ -0,0 +1,53 @@
|
||||
@core @core_badges
|
||||
Feature: Delete course badge already awarded
|
||||
As a teacher
|
||||
I can delete awarded course badge
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Delete course badge already awarded to student
|
||||
Given the following "core_badges > Badges" exist:
|
||||
| name | course | description | image | status | type |
|
||||
| <badgename> | C1 | <badgename> description | badges/tests/behat/badge.png | active | 2 |
|
||||
And the following "core_badges > Criterias" exist:
|
||||
| badge | role |
|
||||
| <badgename> | editingteacher |
|
||||
And the following "core_badges > Issued badges" exist:
|
||||
| badge | user |
|
||||
| <badgename> | student1 |
|
||||
When I am on the "Course 1" "enrolled users" page logged in as "teacher1"
|
||||
And I click on "Student 1" "link"
|
||||
Then I should see "<badgename>"
|
||||
And I am on the "Course 1" course page
|
||||
# Navigate to Manage Badges page in order to delete the badge
|
||||
And I navigate to "Badges > Manage badges" in current page administration
|
||||
# Delete the badge
|
||||
And I open the action menu in "<badgename>" "table_row"
|
||||
And I choose "Delete" in the open action menu
|
||||
And I press "<deleteoption>"
|
||||
And I am on the "Course 1" "enrolled users" page
|
||||
And I click on "Student 1" "link"
|
||||
# Confirm that Badge 1 is retained as awarded badge but Badge 2 is not
|
||||
And I <visibility> see "<badgename>"
|
||||
And I am on the "Course 1" course page
|
||||
# Navigate to Badges page to confirm that no badges exist, hence, Manage badges would not exist
|
||||
And I navigate to "Badges" in current page administration
|
||||
# Confirm that badges are sucessfully deleted
|
||||
And I should see "There are currently no badges available for users to earn."
|
||||
|
||||
Examples:
|
||||
| badgename | deleteoption | visibility |
|
||||
| Badge 1 | Delete and keep existing issued badges | should |
|
||||
| Badge 2 | Delete and remove existing issued badges | should not |
|
||||
@@ -25,11 +25,16 @@ Feature: Add a comment to the comments block
|
||||
Scenario: Add a comment with Javascript enabled
|
||||
When I add "I'm a comment from student1" comment to comments block
|
||||
Then I should see "I'm a comment from student1"
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I should see "I'm a comment from student1"
|
||||
|
||||
Scenario: Add a comment with Javascript disabled
|
||||
When I follow "Show comments"
|
||||
And I add "I'm a comment from student1" comment to comments block
|
||||
Then I should see "I'm a comment from student1"
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I follow "Show comments"
|
||||
And I should see "I'm a comment from student1"
|
||||
|
||||
@javascript
|
||||
Scenario: Test comment block pagination
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
@block @block_comments
|
||||
Feature: Enable Block comments on a course page and view comments
|
||||
In order to enable the comments block on a course page
|
||||
As a teacher
|
||||
I can add the comments block to the course page
|
||||
|
||||
Scenario: Add the comments block on the course page and add comments
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Frist | teacher1@example.com |
|
||||
| student1 | Student | First | student1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| comments | Course | C1 | course-view-* | side-pre |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I follow "Show comments"
|
||||
And I add "I'm a comment from the teacher" comment to comments block
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
And I follow "Show comments"
|
||||
Then I should see "I'm a comment from the teacher"
|
||||
@@ -176,7 +176,23 @@ class behat_calendar extends behat_base {
|
||||
* @return void
|
||||
*/
|
||||
public function i_am_viewing_site_calendar() {
|
||||
$url = new moodle_url('/calendar/view.php', ['view' => 'month']);
|
||||
$this->i_am_viewing_calendar_in_view('month');
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigate to a specific view in the calendar.
|
||||
*
|
||||
* @Given /^I am viewing calendar in "([^"]+)" view$/
|
||||
* @param string $view The calendar view ('month', 'day' and 'upcoming') to navigate to.
|
||||
* @return void
|
||||
*/
|
||||
public function i_am_viewing_calendar_in_view(string $view): void {
|
||||
|
||||
if (!in_array($view, ['month', 'day', 'upcoming'])) {
|
||||
throw new Exception("Invalid calendar view. Allowed values are: 'month', 'day' and 'upcoming'");
|
||||
}
|
||||
|
||||
$url = new moodle_url('/calendar/view.php', ['view' => $view]);
|
||||
$this->execute('behat_general::i_visit', [$url]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,7 +528,7 @@ class manager {
|
||||
$data['customrules'] = $customdata ? json_encode($customdata) : null;
|
||||
$defaults['customrules'] = null;
|
||||
}
|
||||
$data = array_intersect_key($data, $defaults);
|
||||
$data = array_merge($defaults, $data);
|
||||
|
||||
// Get names of the affected modules.
|
||||
list($modidssql, $params) = $DB->get_in_or_equal($modids);
|
||||
|
||||
@@ -29,13 +29,19 @@ Feature: Allow teachers to edit the default activity completion rules in a cours
|
||||
And I set the field "Course completion tertiary navigation" to "Default activity completion"
|
||||
And I click on "Expand Assignment" "button"
|
||||
And I set the following fields to these values:
|
||||
| Add requirements | 1 |
|
||||
| completionview_assign | 0 |
|
||||
| completionusegrade_assign | 1 |
|
||||
| completionsubmit_assign | 1 |
|
||||
| Add requirements | 1 |
|
||||
| completionview_assign | 1 |
|
||||
| completionusegrade_assign | 1 |
|
||||
| completionsubmit_assign | 1 |
|
||||
And I should not see "Cancel" in the "[data-region='activitycompletion-forum']" "css_element"
|
||||
And I click on "Save changes" "button" in the "[data-region='activitycompletion-assign']" "css_element"
|
||||
Then I should see "Changes saved"
|
||||
And I navigate to "Course completion" in current page administration
|
||||
And I set the field "Course completion tertiary navigation" to "Default activity completion"
|
||||
And I click on "Expand Assignment" "button"
|
||||
And I set the following fields to these values:
|
||||
| completionview_assign | 0 |
|
||||
And I click on "Save changes" "button" in the "[data-region='activitycompletion-assign']" "css_element"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I press "Add an activity or resource"
|
||||
And I click on "Add a new Assignment" "link" in the "Add an activity or resource" "dialogue"
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
namespace core_courseformat\output\local\content;
|
||||
|
||||
use cm_info;
|
||||
use context_course;
|
||||
use core\output\named_templatable;
|
||||
use core_availability\info_module;
|
||||
use core_courseformat\base as course_format;
|
||||
@@ -300,7 +301,13 @@ class cm implements named_templatable, renderable {
|
||||
* @return bool if the cm has editor data
|
||||
*/
|
||||
protected function add_editor_data(stdClass &$data, renderer_base $output): bool {
|
||||
if (!$this->format->show_editor()) {
|
||||
$course = $this->format->get_course();
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$editcaps = [];
|
||||
if (has_capability('moodle/course:activityvisibility', $coursecontext)) {
|
||||
$editcaps = ['moodle/course:activityvisibility'];
|
||||
}
|
||||
if (!$this->format->show_editor($editcaps)) {
|
||||
return false;
|
||||
}
|
||||
$returnsection = $this->format->get_section_number();
|
||||
|
||||
@@ -283,11 +283,16 @@ class section implements named_templatable, renderable {
|
||||
* @return bool if the cm has name data
|
||||
*/
|
||||
protected function add_editor_data(stdClass &$data, renderer_base $output): bool {
|
||||
if (!$this->format->show_editor()) {
|
||||
$course = $this->format->get_course();
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
$editcaps = [];
|
||||
if (has_capability('moodle/course:sectionvisibility', $coursecontext)) {
|
||||
$editcaps = ['moodle/course:sectionvisibility'];
|
||||
}
|
||||
if (!$this->format->show_editor($editcaps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$course = $this->format->get_course();
|
||||
if (empty($this->hidecontrols)) {
|
||||
$controlmenu = new $this->controlmenuclass($this->format, $this->section);
|
||||
$data->controlmenu = $controlmenu->export_for_template($output);
|
||||
|
||||
+1
-1
@@ -1697,7 +1697,7 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
|
||||
}
|
||||
|
||||
// Move (only for component compatible formats).
|
||||
if ($usecomponents) {
|
||||
if ($hasmanageactivities && $usecomponents) {
|
||||
$actions['move'] = new action_menu_link_secondary(
|
||||
new moodle_url($baseurl, [
|
||||
'sesskey' => sesskey(),
|
||||
|
||||
+3
-7
@@ -183,12 +183,7 @@ class graded_users_iterator {
|
||||
}
|
||||
}
|
||||
|
||||
$userfieldsapi = \core_user\fields::for_identity($coursecontext, false)->with_userpic();
|
||||
$userfields = $userfieldsapi->get_sql('u', false, '', '', false)->selects;
|
||||
|
||||
// This need to be fixed - webservices in grade/report/user/classes/external/user.php don't check permission properly.
|
||||
$userfields .= ', u.idnumber, u.institution, u.department';
|
||||
|
||||
$userfields = 'u.*';
|
||||
$customfieldssql = '';
|
||||
if ($this->allowusercustomfields && !empty($CFG->grade_export_customprofilefields)) {
|
||||
$customfieldscount = 0;
|
||||
@@ -222,7 +217,8 @@ class graded_users_iterator {
|
||||
$this->users_rs = $DB->get_recordset_sql($users_sql, $params);
|
||||
|
||||
if (!$this->onlyactive) {
|
||||
$this->suspendedusers = get_suspended_userids($coursecontext);
|
||||
$context = context_course::instance($this->course->id);
|
||||
$this->suspendedusers = get_suspended_userids($context);
|
||||
} else {
|
||||
$this->suspendedusers = array();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Automatically generated strings for Moodle installer
|
||||
*
|
||||
* Do not edit this file manually! It contains just a subset of strings
|
||||
* needed during the very first steps of installation. This file was
|
||||
* generated automatically by export-installer.php (which is part of AMOS
|
||||
* {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
|
||||
* list of strings defined in /install/stringnames.txt.
|
||||
*
|
||||
* @package installer
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$string['language'] = 'Lingua';
|
||||
$string['moodlelogo'] = 'Mercu Moodle';
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -1,4 +1,4 @@
|
||||
define("core/str",["exports","jquery","core/ajax","core/localstorage"],(function(_exports,_jquery,_ajax,_localstorage){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
define("core/str",["exports","jquery","core/ajax","core/config","core/localstorage"],(function(_exports,_jquery,_ajax,_config,_localstorage){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Fetch and return language strings.
|
||||
*
|
||||
@@ -7,6 +7,6 @@ define("core/str",["exports","jquery","core/ajax","core/localstorage"],(function
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since 2.9
|
||||
*
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.get_strings=_exports.get_string=_exports.getStrings=_exports.getString=_exports.cache_strings=void 0,_jquery=_interopRequireDefault(_jquery),_ajax=_interopRequireDefault(_ajax),_localstorage=_interopRequireDefault(_localstorage);let promiseCache=[];_exports.get_string=(key,component,param,lang)=>get_strings([{key:key,component:component,param:param,lang:lang}]).then((results=>results[0]));_exports.getString=(key,component,param,lang)=>getRequestedStrings([{key:key,component:component,param:param,lang:lang}])[0];_exports.getStrings=requests=>Promise.all(getRequestedStrings(requests));const getRequestedStrings=requests=>{let requestData=[];const pageLang=(0,_jquery.default)("html").attr("lang").replace(/-/g,"_"),stringPromises=requests.map((request=>{let{component:component,key:key,param:param,lang:lang=pageLang}=request;component||(component="core");const cacheKey=(_ref=>{let{key:key,component:component,lang:lang=pageLang}=_ref;return"core_str/".concat(key,"/").concat(component,"/").concat(lang)})({key:key,component:component,lang:lang}),buildReturn=promise=>(promiseCache[cacheKey]=promise,promise);if(component in M.str&&key in M.str[component])return buildReturn(new Promise((resolve=>{resolve(M.util.get_string(key,component,param,lang))})));const cached=_localstorage.default.get(cacheKey);return cached?(M.str[component]={...M.str[component],[key]:cached},buildReturn(new Promise((resolve=>{resolve(M.util.get_string(key,component,param,lang))})))):cacheKey in promiseCache?buildReturn(promiseCache[cacheKey]).then((()=>M.util.get_string(key,component,param,lang))):buildReturn(new Promise(((resolve,reject)=>{requestData.push({methodname:"core_get_string",args:{stringid:key,stringparams:[],component:component,lang:lang},done:str=>{M.str[component]={...M.str[component],[key]:str},_localstorage.default.set(cacheKey,str),resolve(M.util.get_string(key,component,param,lang))},fail:reject})})))}));return requestData.length&&_ajax.default.call(requestData,!0,!1,!1,0,M.cfg.langrev),stringPromises},get_strings=requests=>_jquery.default.when.apply(_jquery.default,getRequestedStrings(requests)).then((function(){for(var _len=arguments.length,strings=new Array(_len),_key=0;_key<_len;_key++)strings[_key]=arguments[_key];return strings}));_exports.get_strings=get_strings;_exports.cache_strings=strings=>{const defaultLang=(0,_jquery.default)("html").attr("lang").replace(/-/g,"_");strings.forEach((_ref2=>{let{key:key,component:component,value:value,lang:lang=defaultLang}=_ref2;const cacheKey=["core_str",key,component,lang].join("/");component in M.str&&key in M.str[component]||(component in M.str||(M.str[component]={}),M.str[component][key]=value),_localstorage.default.get(cacheKey)||_localstorage.default.set(cacheKey,value),cacheKey in promiseCache||(promiseCache[cacheKey]=_jquery.default.Deferred().resolve(value).promise())}))}}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.get_strings=_exports.get_string=_exports.getStrings=_exports.getString=_exports.cache_strings=void 0,_jquery=_interopRequireDefault(_jquery),_ajax=_interopRequireDefault(_ajax),_config=_interopRequireDefault(_config),_localstorage=_interopRequireDefault(_localstorage);let promiseCache=[];_exports.get_string=(key,component,param,lang)=>get_strings([{key:key,component:component,param:param,lang:lang}]).then((results=>results[0]));_exports.getString=(key,component,param,lang)=>getRequestedStrings([{key:key,component:component,param:param,lang:lang}])[0];_exports.getStrings=requests=>Promise.all(getRequestedStrings(requests));const getRequestedStrings=requests=>{let requestData=[];const pageLang=_config.default.language,stringPromises=requests.map((request=>{let{component:component,key:key,param:param,lang:lang=pageLang}=request;component||(component="core");const cacheKey=(_ref=>{let{key:key,component:component,lang:lang=pageLang}=_ref;return"core_str/".concat(key,"/").concat(component,"/").concat(lang)})({key:key,component:component,lang:lang}),buildReturn=promise=>(promiseCache[cacheKey]=promise,promise);if(component in M.str&&key in M.str[component])return buildReturn(new Promise((resolve=>{resolve(M.util.get_string(key,component,param,lang))})));const cached=_localstorage.default.get(cacheKey);return cached?(M.str[component]={...M.str[component],[key]:cached},buildReturn(new Promise((resolve=>{resolve(M.util.get_string(key,component,param,lang))})))):cacheKey in promiseCache?buildReturn(promiseCache[cacheKey]).then((()=>M.util.get_string(key,component,param,lang))):buildReturn(new Promise(((resolve,reject)=>{requestData.push({methodname:"core_get_string",args:{stringid:key,stringparams:[],component:component,lang:lang},done:str=>{M.str[component]={...M.str[component],[key]:str},_localstorage.default.set(cacheKey,str),resolve(M.util.get_string(key,component,param,lang))},fail:reject})})))}));return requestData.length&&_ajax.default.call(requestData,!0,!1,!1,0,M.cfg.langrev),stringPromises},get_strings=requests=>_jquery.default.when.apply(_jquery.default,getRequestedStrings(requests)).then((function(){for(var _len=arguments.length,strings=new Array(_len),_key=0;_key<_len;_key++)strings[_key]=arguments[_key];return strings}));_exports.get_strings=get_strings;_exports.cache_strings=strings=>{strings.forEach((_ref2=>{let{key:key,component:component,value:value,lang:lang=_config.default.language}=_ref2;const cacheKey=["core_str",key,component,lang].join("/");component in M.str&&key in M.str[component]||(component in M.str||(M.str[component]={}),M.str[component][key]=value),_localstorage.default.get(cacheKey)||_localstorage.default.set(cacheKey,value),cacheKey in promiseCache||(promiseCache[cacheKey]=_jquery.default.Deferred().resolve(value).promise())}))}}));
|
||||
|
||||
//# sourceMappingURL=str.min.js.map
|
||||
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -5,6 +5,6 @@
|
||||
* @copyright 2017 Ryan Wyllie <ryan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define("core/user_date",["jquery","core/ajax","core/sessionstorage","core/config"],(function($,Ajax,Storage,Config){var promisesCache={},getKey=function(request){return"core_user_date/"+$("html").attr("lang").replace(/-/g,"_")+"/"+Config.usertimezone+"/"+request.timestamp+"/"+request.format},loadDatesFromServer=function(dates){var args=dates.map((function(data){var fixDay=data.hasOwnProperty("fixday")?data.fixday:1,fixHour=data.hasOwnProperty("fixhour")?data.fixhour:1;return{timestamp:data.timestamp,format:data.format,type:data.type||null,fixday:fixDay,fixhour:fixHour}})),request={methodname:"core_get_user_dates",args:{contextid:Config.contextid,timestamps:args}};return Ajax.call([request],!0,!0)[0].then((function(results){results.dates.forEach((function(value,index){var date=dates[index];!function(key,value){Storage.set(key,value)}(getKey(date),value),date.deferred.resolve(value)}))})).catch((function(ex){dates.forEach((function(date){date.deferred.reject(ex)}))}))};return{get:function(requests){var ajaxRequests=[],promises=[];return requests.forEach((function(request){var key=getKey(request);if(function(key){return void 0!==promisesCache[key]}(key))promises.push(function(key){return promisesCache[key]}(key));else{var deferred=$.Deferred(),cached=function(key){return Storage.get(key)}(key);cached?deferred.resolve(cached):(request.deferred=deferred,ajaxRequests.push(request)),function(key,promise){promisesCache[key]=promise}(key,deferred.promise()),promises.push(deferred.promise())}})),ajaxRequests.length&&loadDatesFromServer(ajaxRequests),$.when.apply($,promises).then((function(){return 1===arguments.length?[arguments[0]]:Array.apply(null,arguments)}))},getUserMidnightForTimestamp:function(timestamp,todayMidnight){var future=timestamp>todayMidnight,diffSeconds=Math.abs(timestamp-todayMidnight),diffDaysInSeconds=86400*(future?Math.floor(diffSeconds/86400):Math.ceil(diffSeconds/86400));return future?todayMidnight+diffDaysInSeconds:todayMidnight-diffDaysInSeconds}}}));
|
||||
define("core/user_date",["jquery","core/ajax","core/sessionstorage","core/config"],(function($,Ajax,Storage,Config){var promisesCache={},getKey=function(request){return"core_user_date/"+Config.language+"/"+Config.usertimezone+"/"+request.timestamp+"/"+request.format},loadDatesFromServer=function(dates){var args=dates.map((function(data){var fixDay=data.hasOwnProperty("fixday")?data.fixday:1,fixHour=data.hasOwnProperty("fixhour")?data.fixhour:1;return{timestamp:data.timestamp,format:data.format,type:data.type||null,fixday:fixDay,fixhour:fixHour}})),request={methodname:"core_get_user_dates",args:{contextid:Config.contextid,timestamps:args}};return Ajax.call([request],!0,!0)[0].then((function(results){results.dates.forEach((function(value,index){var date=dates[index];!function(key,value){Storage.set(key,value)}(getKey(date),value),date.deferred.resolve(value)}))})).catch((function(ex){dates.forEach((function(date){date.deferred.reject(ex)}))}))};return{get:function(requests){var ajaxRequests=[],promises=[];return requests.forEach((function(request){var key=getKey(request);if(function(key){return void 0!==promisesCache[key]}(key))promises.push(function(key){return promisesCache[key]}(key));else{var deferred=$.Deferred(),cached=function(key){return Storage.get(key)}(key);cached?deferred.resolve(cached):(request.deferred=deferred,ajaxRequests.push(request)),function(key,promise){promisesCache[key]=promise}(key,deferred.promise()),promises.push(deferred.promise())}})),ajaxRequests.length&&loadDatesFromServer(ajaxRequests),$.when.apply($,promises).then((function(){return 1===arguments.length?[arguments[0]]:Array.apply(null,arguments)}))},getUserMidnightForTimestamp:function(timestamp,todayMidnight){var future=timestamp>todayMidnight,diffSeconds=Math.abs(timestamp-todayMidnight),diffDaysInSeconds=86400*(future?Math.floor(diffSeconds/86400):Math.ceil(diffSeconds/86400));return future?todayMidnight+diffDaysInSeconds:todayMidnight-diffDaysInSeconds}}}));
|
||||
|
||||
//# sourceMappingURL=user_date.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -346,7 +346,7 @@ export default class Loader {
|
||||
component,
|
||||
template: name,
|
||||
themename: theme,
|
||||
lang: $('html').attr('lang').replace(/-/g, '_')
|
||||
lang: config.language,
|
||||
}
|
||||
});
|
||||
// Remember the index in the requests list for this template so that
|
||||
|
||||
+4
-5
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
import $ from 'jquery';
|
||||
import Ajax from 'core/ajax';
|
||||
import Config from 'core/config';
|
||||
import LocalStorage from 'core/localstorage';
|
||||
|
||||
/**
|
||||
@@ -129,7 +130,7 @@ export const getStrings = (requests) => Promise.all(getRequestedStrings(requests
|
||||
*/
|
||||
const getRequestedStrings = (requests) => {
|
||||
let requestData = [];
|
||||
const pageLang = $('html').attr('lang').replace(/-/g, '_');
|
||||
const pageLang = Config.language;
|
||||
|
||||
// Helper function to construct the cache key.
|
||||
const getCacheKey = ({key, component, lang = pageLang}) => `core_str/${key}/${component}/${lang}`;
|
||||
@@ -256,13 +257,11 @@ export const get_strings = (requests) => {
|
||||
* @param {string} strings.key The string identifer to fetch
|
||||
* @param {string} strings.value The string value
|
||||
* @param {string} [strings.component='core'] The componet to fetch from
|
||||
* @param {string} [strings.lang] The language to fetch a string for. Defaults to current page language.
|
||||
* @param {string} [strings.lang=Config.language] The language to fetch a string for. Defaults to current page language.
|
||||
*/
|
||||
// eslint-disable-next-line camelcase
|
||||
export const cache_strings = (strings) => {
|
||||
const defaultLang = $('html').attr('lang').replace(/-/g, '_');
|
||||
|
||||
strings.forEach(({key, component, value, lang = defaultLang}) => {
|
||||
strings.forEach(({key, component, value, lang = Config.language}) => {
|
||||
const cacheKey = ['core_str', key, component, lang].join('/');
|
||||
|
||||
// Check M.str caching.
|
||||
|
||||
@@ -36,9 +36,8 @@ define(['jquery', 'core/ajax', 'core/sessionstorage', 'core/config'],
|
||||
* @return {string}
|
||||
*/
|
||||
var getKey = function(request) {
|
||||
var language = $('html').attr('lang').replace(/-/g, '_');
|
||||
return 'core_user_date/' +
|
||||
language + '/' +
|
||||
Config.language + '/' +
|
||||
Config.usertimezone + '/' +
|
||||
request.timestamp + '/' +
|
||||
request.format;
|
||||
|
||||
@@ -470,13 +470,7 @@ class behat_core_generator extends behat_generator_base {
|
||||
}
|
||||
}
|
||||
|
||||
// Custom exception.
|
||||
try {
|
||||
$this->datagenerator->create_module($activityname, $data, $cmoptions);
|
||||
} catch (coding_exception $e) {
|
||||
throw new Exception('\'' . $activityname . '\' activity can not be added using this step,' .
|
||||
' use the step \'I add a "ACTIVITY_OR_RESOURCE_NAME_STRING" to section "SECTION_NUMBER"\' instead');
|
||||
}
|
||||
$this->datagenerator->create_module($activityname, $data, $cmoptions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -144,10 +144,8 @@ class repository extends base {
|
||||
if ($hassiteconfig && $this->is_enabled()) {
|
||||
// Completely no access to repository setting when it is not enabled.
|
||||
$sectionname = $this->get_settings_section_name();
|
||||
$settingsurl = new moodle_url('/admin/repository.php',
|
||||
array('sesskey' => sesskey(), 'action' => 'edit', 'repos' => $this->name));
|
||||
$settings = new admin_externalpage($sectionname, $this->displayname,
|
||||
$settingsurl, 'moodle/site:config', false);
|
||||
new moodle_url('/admin/repository.php', ['action' => 'edit', 'repos' => $this->name]), 'moodle/site:config', false);
|
||||
$adminroot->add($parentnodename, $settings);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +324,7 @@ class page_requirements_manager {
|
||||
'admin' => $CFG->admin,
|
||||
'svgicons' => $page->theme->use_svg_icons(),
|
||||
'usertimezone' => usertimezone(),
|
||||
'language' => current_language(),
|
||||
'courseId' => isset($courseid) ? (int) $courseid : 0,
|
||||
'courseContextId' => isset($coursecontext) ? $coursecontext->id : 0,
|
||||
'contextid' => $contextid,
|
||||
|
||||
@@ -200,7 +200,7 @@ class behat_general extends behat_base {
|
||||
/**
|
||||
* Switches to the specified window. Useful when interacting with popup windows.
|
||||
*
|
||||
* @Given /^I switch to "(?P<window_name_string>(?:[^"]|\\")*)" window$/
|
||||
* @Given /^I switch to "(?P<window_name_string>(?:[^"]|\\")*)" (window|tab)$/
|
||||
* @param string $windowname
|
||||
*/
|
||||
public function switch_to_window($windowname) {
|
||||
@@ -232,7 +232,7 @@ class behat_general extends behat_base {
|
||||
/**
|
||||
* Switches to the main Moodle window. Useful when you finish interacting with popup windows.
|
||||
*
|
||||
* @Given /^I switch to the main window$/
|
||||
* @Given /^I switch to the main (window|tab)$/
|
||||
*/
|
||||
public function switch_to_the_main_window() {
|
||||
$this->switch_to_window(self::MAIN_WINDOW_NAME);
|
||||
|
||||
@@ -965,6 +965,63 @@ class behat_navigation extends behat_base {
|
||||
throw new Exception('Unrecognised core page type "' . $type . '."');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab with given name on the same URL as current page and switches to it.
|
||||
*
|
||||
* @param string $name Tab name that can be used for switching later (no whitespace)
|
||||
* @When /^I open a tab named "(?<name>[^"]*)" on the current page$/
|
||||
*/
|
||||
public function i_open_a_tab_on_the_current_page(string $name): void {
|
||||
$this->open_tab($name, 'location.href');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab with given name on specified page, and switches to it.
|
||||
*
|
||||
* @param string $name Tab name that can be used for switching later (no whitespace)
|
||||
* @param string $page Page name
|
||||
* @When /^I open a tab named "(?<name>[^"]*)" on the "(?<page>[^"]*)" page$/
|
||||
*/
|
||||
public function i_open_a_tab_on_the_page(string $name, string $page): void {
|
||||
if ($page === 'current') {
|
||||
$jstarget = 'location.href';
|
||||
} else {
|
||||
$jstarget = '"' . addslashes_js($this->resolve_page_helper($page)->out(false)) . '"';
|
||||
}
|
||||
$this->open_tab($name, $jstarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab with given name (on specified page), and switches to it.
|
||||
*
|
||||
* @param string $name Tab name that can be used for switching later (no whitespace)
|
||||
* @param string $identifier Page identifier
|
||||
* @param string $page Page type
|
||||
* @When /^I open a tab named "(?<name>[^"]*)" on the "(?<identifier>[^"]*)" "(?<page>[^"]*)" page$/
|
||||
*/
|
||||
public function i_open_a_tab_on_the_page_instance(string $name, string $identifier, string $page): void {
|
||||
$this->open_tab($name, '"' . addslashes_js(
|
||||
$this->resolve_page_instance_helper($identifier, $page)->out(false)) . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a new tab at the given target URL.
|
||||
*
|
||||
* @param string $name Name for tab
|
||||
* @param string $jstarget Target in JavaScript syntax, i.e. if a string, must be quoted
|
||||
*/
|
||||
protected function open_tab(string $name, string $jstarget): void {
|
||||
// Tab names aren't allowed spaces, and our JavaScript below doesn't do any escaping.
|
||||
if (clean_param($name, PARAM_ALPHANUMEXT) !== $name) {
|
||||
throw new Exception('Tab name may not contain whitespace or special characters: "' . $name . '"');
|
||||
}
|
||||
|
||||
// Normally you can't open a tab unless in response to a user action, but presumably Behat
|
||||
// is exempt from this restriction, because it works to just open it directly.
|
||||
$this->execute_script('window.open(' . $jstarget . ', "' . $name . '");');
|
||||
$this->execute('behat_general::switch_to_window', [$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the course homepage. (Consider using 'I am on the "shortname" "Course" page' step instead.)
|
||||
*
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.3.2 ===
|
||||
|
||||
* The current page language is available in new `core/config` language property for Javascript modules
|
||||
|
||||
=== 4.3.1 ===
|
||||
|
||||
* Added modalform config object `moduleName` param that can be used to define alternative modal type for the modalform. By default 'core/modal_save_cancel' is used.
|
||||
|
||||
@@ -17,18 +17,19 @@ Feature: Chat calendar entries
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
|
||||
Scenario: Create a chat activity and do not publish the start date to the calendar
|
||||
Scenario Outline: Create a chat activity with repeated chat times set
|
||||
# Create an activity with repeated chat times
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | schedule |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 0 |
|
||||
| activity | course | name | schedule |
|
||||
| chat | C1 | Chat 1 | <scheduleset> |
|
||||
And I log in as "teacher1"
|
||||
When I follow "Calendar" in the user menu
|
||||
Then I should not see "Test chat name"
|
||||
# Confirm Chat activity visibility based on schedule
|
||||
When I am viewing calendar in "upcoming" view
|
||||
Then I <chatvisibility> see "Chat 1"
|
||||
|
||||
Scenario: Create a chat activity and publish the start date to the calendar
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | schedule |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 1 |
|
||||
And I log in as "teacher1"
|
||||
When I follow "Calendar" in the user menu
|
||||
Then I should see "Test chat name"
|
||||
Examples:
|
||||
| scheduleset | chatvisibility |
|
||||
| 0 | should not |
|
||||
| 1 | should |
|
||||
| 2 | should |
|
||||
| 3 | should |
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
@mod @mod_chat @javascript
|
||||
Feature: View past chat sessions
|
||||
In order for students to view past chat sessions
|
||||
As a teacher
|
||||
I need to be able to change the mod/chat:readlog permission for students
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | One | teacher1@example.com |
|
||||
| student1 | Student | One | student1@example.com |
|
||||
And the following "course" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
|
||||
Scenario Outline: View past chat sessions
|
||||
# Display or hide past chat session based on example data
|
||||
Given the following "activities" exist:
|
||||
| activity | course | name | studentlogs |
|
||||
| chat | C1 | Chat 1 | <studentlogvalue> |
|
||||
And I am on the "Chat 1" "chat activity" page logged in as teacher1
|
||||
# Display or hide past chat session by default based on mod/chat:readlog setting
|
||||
And the following "role capability" exists:
|
||||
| role | student |
|
||||
| mod/chat:readlog | <readpermission> |
|
||||
# Enter chat activity to create a session
|
||||
And I click on "Enter the chat" "link"
|
||||
# Close chat window
|
||||
When I close all opened windows
|
||||
And I reload the page
|
||||
# Confirm that past chat sessions is always visible for teacher
|
||||
Then I should see "Past sessions"
|
||||
# Confirm past chat sessions visibility for student based on settings
|
||||
And I am on the "Chat 1" "chat activity" page logged in as student1
|
||||
And I <sessionvisibility> see "Past sessions"
|
||||
|
||||
# Regardless of studentlogvalue value if readpermission is allowed, then Past sessions will be visible for students
|
||||
Examples:
|
||||
| studentlogvalue | readpermission | sessionvisibility |
|
||||
| 0 | allow | should |
|
||||
| 1 | allow | should |
|
||||
| 0 | prohibit | should not |
|
||||
| 1 | prohibit | should |
|
||||
@@ -0,0 +1,82 @@
|
||||
@mod @mod_lesson
|
||||
Feature: Retake lesson activity
|
||||
In order for student to retake a lesson activity
|
||||
As a teacher
|
||||
I should be able to allow retakes
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
# Generate lesson with retakes enabled, maxgrade = 100 and handling of re-takes = use mean
|
||||
And the following "activities" exist:
|
||||
| activity | name | course | retake | grade[modgrade_point] | usemaxgrade |
|
||||
| lesson | Test lesson name | C1 | 1 | 100 | 0 |
|
||||
# Generate question pages
|
||||
And the following "mod_lesson > page" exist:
|
||||
| lesson | qtype | title | content |
|
||||
| Test lesson name | multichoice | Question 1 | Which is not a plant? |
|
||||
| Test lesson name | multichoice | Question 2 | Which is a plant? |
|
||||
| Test lesson name | multichoice | Question 3 | Which is a plant and a colour? |
|
||||
# Generate question answers
|
||||
And the following "mod_lesson > answers" exist:
|
||||
| page | answer | jumpto | score |
|
||||
| Question 1 | Brown | Next page | 1 |
|
||||
| Question 1 | Lavender | Next page | 0 |
|
||||
| Question 2 | Brown | Next page | 0 |
|
||||
| Question 2 | Lavender | Next page | 1 |
|
||||
| Question 3 | Brown | Next page | 0 |
|
||||
| Question 3 | Lavender | Next page | 1 |
|
||||
|
||||
Scenario: A student can retake a lesson
|
||||
# First attempt - all correct
|
||||
Given I am on the "Test lesson name" "lesson activity" page logged in as student1
|
||||
And I set the following fields to these values:
|
||||
| Brown | 1 |
|
||||
And I press "Submit"
|
||||
And I set the following fields to these values:
|
||||
| Lavender | 1 |
|
||||
And I press "Submit"
|
||||
And I set the following fields to these values:
|
||||
| Lavender | 1 |
|
||||
And I press "Submit"
|
||||
# Confirm that lesson can be retaken
|
||||
When I am on the "Test lesson name" "lesson activity" page
|
||||
Then I should see "Which is not a plant?"
|
||||
# Second attempt - only 1 correct
|
||||
And I set the following fields to these values:
|
||||
| Lavender | 1 |
|
||||
And I press "Submit"
|
||||
And I set the following fields to these values:
|
||||
| Brown | 1 |
|
||||
And I press "Submit"
|
||||
And I set the following fields to these values:
|
||||
| Lavender | 1 |
|
||||
And I press "Submit"
|
||||
# Check that grade is 66.67 (mean of the 2 attempts)
|
||||
And I click on "View grades" "link"
|
||||
And "Test lesson name" row "Grade" column of "generaltable" table should contain "66.67"
|
||||
# Change handling of re-takes = use maximum
|
||||
And I am on the "Test lesson name" "lesson activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Handling of re-takes | Use maximum |
|
||||
And I press "Save and display"
|
||||
# Confirm that lesson grade is the maximum of the 2 attempts (100)
|
||||
And I am on the "Course 1" "grades > user > View" page logged in as student1
|
||||
And "Test lesson name" row "Grade" column of "generaltable" table should contain "100.00"
|
||||
# Disable lesson retake
|
||||
And I am on the "Test lesson name" "lesson activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Re-takes allowed | No |
|
||||
And I press "Save and display"
|
||||
# Confirm lesson cannot be retaken
|
||||
And I am on the "Test lesson name" "lesson activity" page logged in as student1
|
||||
And I should see "You are not allowed to retake this lesson."
|
||||
@@ -16,51 +16,76 @@ Feature: In a lesson activity, students can review the answers they gave to ques
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
And the following "activity" exist:
|
||||
| activity | name | course | idnumber |
|
||||
| lesson | Test lesson name | C1 | lesson1 |
|
||||
And the following "activity" exists:
|
||||
| activity | lesson |
|
||||
| name | Test lesson name |
|
||||
| course | C1 |
|
||||
| idnumber | lesson1 |
|
||||
# Display ongoing score = Yes
|
||||
| ongoing | 1 |
|
||||
# Slideshow = Yes
|
||||
| slideshow | 1 |
|
||||
# Maximum number of answers = 10
|
||||
| maxanswers | 10 |
|
||||
# Allow student review = Yes
|
||||
| modattempts | 1 |
|
||||
# Maximum number of attempts per question
|
||||
| maxattempts | 3 |
|
||||
# Custom scoring = No
|
||||
| custom | 0 |
|
||||
# Re-takes allowed = Yes
|
||||
| retake | 1 |
|
||||
And the following "mod_lesson > pages" exist:
|
||||
| lesson | qtype | title | content |
|
||||
| Test lesson name | numeric | Hardest question ever | 1 + 1? |
|
||||
| Test lesson name | truefalse | Next question | Paper is made from trees. |
|
||||
And the following "mod_lesson > answers" exist:
|
||||
| page | answer | response | jumpto | score |
|
||||
| Hardest question ever | 2 | Correct answer | Next page | 1 |
|
||||
| Hardest question ever | 1 | Incorrect answer | This page | 0 |
|
||||
| Next question | True | Correct | Next page | 1 |
|
||||
| Next question | False | Wrong | This page | 0 |
|
||||
And I am on the "Test lesson name" "lesson activity editing" page logged in as teacher1
|
||||
And I set the following fields to these values:
|
||||
| Display ongoing score | Yes |
|
||||
| Slideshow | Yes |
|
||||
| Maximum number of answers | 10 |
|
||||
| Allow student review | Yes |
|
||||
| Maximum number of attempts per question | 3 |
|
||||
| Custom scoring | No |
|
||||
| Re-takes allowed | Yes |
|
||||
And I press "Save and display"
|
||||
| page | answer | response | jumpto | score |
|
||||
| Hardest question ever | 2 | Correct answer 1 | Next page | 1 |
|
||||
| Hardest question ever | 1 | Incorrect answer 1 | This page | 0 |
|
||||
| Next question | True | Correct answer 2 | Next page | 1 |
|
||||
| Next question | False | Incorrect answer 2 | This page | 0 |
|
||||
And I am on the "Test lesson name" "lesson activity" page logged in as student1
|
||||
And I should see "You have answered 0 correctly out of 0 attempts."
|
||||
And I should see "1 + 1?"
|
||||
And I wait "1" seconds
|
||||
And I set the following fields to these values:
|
||||
| Your answer | 1 |
|
||||
And I press "Submit"
|
||||
And I should see "You have answered 0 correctly out of 1 attempts."
|
||||
And I press "Continue"
|
||||
And I should see "1 + 1?"
|
||||
And I wait "1" seconds
|
||||
And I set the following fields to these values:
|
||||
| Your answer | 2 |
|
||||
And I press "Submit"
|
||||
And I should see "You have answered 1 correctly out of 2 attempts."
|
||||
And I press "Continue"
|
||||
And I should see "Paper is made from trees."
|
||||
And I wait "1" seconds
|
||||
And I set the following fields to these values:
|
||||
| True | 1 |
|
||||
And I press "Submit"
|
||||
And I should see "You have answered 2 correctly out of 3 attempts."
|
||||
And I should see "Paper is made from trees."
|
||||
And I press "Continue"
|
||||
And I should see "Congratulations - end of lesson reached"
|
||||
And I should see "Number of questions answered: 2"
|
||||
And I should see "Number of correct answers: 2"
|
||||
And I should see "Your score is 2 (out of 3)."
|
||||
When I follow "Review lesson"
|
||||
Then I should see "You have answered 2 correctly out of 3 attempts."
|
||||
And I should see "1 + 1?"
|
||||
And I press "Next page"
|
||||
And I should see "You have answered 2 correctly out of 3 attempts."
|
||||
And I should see "1 + 1?"
|
||||
And I should see "Correct answer 1"
|
||||
And I press "Continue"
|
||||
And I should see "You have answered 2 correctly out of 3 attempts."
|
||||
And I should see "Paper is made from trees."
|
||||
And I press "Next page"
|
||||
And I should see "You have answered 2 correctly out of 3 attempts."
|
||||
And I should see "Paper is made from trees."
|
||||
And I should see "Correct answer 2"
|
||||
And I press "Continue"
|
||||
And I should see "Congratulations - end of lesson reached"
|
||||
|
||||
+6
-1
@@ -274,7 +274,12 @@ M.mod_quiz.autosave = {
|
||||
window.tinyMCE.on('AddEditor', function(event) {
|
||||
event.editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
// One or more editors might already have been added, so we have to attach
|
||||
// the event handlers to these as well.
|
||||
window.tinyMCE.get().forEach(function(editor) {
|
||||
editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
YUI.add("moodle-mod_quiz-autosave",function(s,e){M.mod_quiz=M.mod_quiz||{},M.mod_quiz.autosave={TINYMCE_DETECTION_DELAY:500,TINYMCE_DETECTION_REPEATS:20,WATCH_HIDDEN_DELAY:1e3,FAILURES_BEFORE_NOTIFY:1,FIRST_SUCCESSFUL_SAVE:-1,SELECTORS:{QUIZ_FORM:"#responseform",VALUE_CHANGE_ELEMENTS:'input, textarea, [contenteditable="true"]',CHANGE_ELEMENTS:"input, select",HIDDEN_INPUTS:"input[type=hidden]",CONNECTION_ERROR:"#connection-error",CONNECTION_OK:"#connection-ok"},AUTOSAVE_HANDLER:M.cfg.wwwroot+"/mod/quiz/autosave.ajax.php",delay:12e4,form:null,dirty:!1,delay_timer:null,save_transaction:null,savefailures:0,editor_change_handler:null,hidden_field_values:{},init:function(e){this.form=s.one(this.SELECTORS.QUIZ_FORM),this.form&&(this.delay=1e3*e,this.form.delegate("valuechange",this.value_changed,this.SELECTORS.VALUE_CHANGE_ELEMENTS,this),this.form.delegate("change",this.value_changed,this.SELECTORS.CHANGE_ELEMENTS,this),this.form.on("submit",this.stop_autosaving,this),require(["core_form/events"],function(e){window.addEventListener(e.eventTypes.uploadChanged,this.value_changed.bind(this))}.bind(this)),this.init_tinymce(this.TINYMCE_DETECTION_REPEATS),this.save_hidden_field_values(),this.watch_hidden_fields())},save_hidden_field_values:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name");t&&(this.hidden_field_values[t]=e.get("value"))},this)},watch_hidden_fields:function(){this.detect_hidden_field_changes(),s.later(this.WATCH_HIDDEN_DELAY,this,this.watch_hidden_fields)},detect_hidden_field_changes:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name"),i=e.get("value");t&&(t in this.hidden_field_values&&i===this.hidden_field_values[t]||(this.hidden_field_values[t]=i,this.value_changed({target:e})))},this)},init_tinymce:function(e){var t;"undefined"!=typeof window.tinyMCE?(this.editor_change_handler=s.bind(this.editor_changed,this),window.tinyMCE.onAddEditor?window.tinyMCE.onAddEditor.add(s.bind(this.init_tinymce_editor,this)):window.tinyMCE.on&&(t=this.start_save_timer_if_necessary.bind(this),window.tinyMCE.on("AddEditor",function(e){e.editor.on("Change Undo Redo keydown",t)}))):0<e&&s.later(this.TINYMCE_DETECTION_DELAY,this,this.init_tinymce,[e-1])},init_tinymce_editor:function(e,t){t.onChange.add(this.editor_change_handler),t.onRedo.add(this.editor_change_handler),t.onUndo.add(this.editor_change_handler),t.onKeyDown.add(this.editor_change_handler)},value_changed:function(e){var t=e.target.getAttribute("name");"thispage"===t||"scrollpos"===t||t&&t.match(/_:flagged$/)||(t=t||"#"+e.target.getAttribute("id"),this.start_save_timer_if_necessary())},editor_changed:function(e){this.start_save_timer_if_necessary()},start_save_timer_if_necessary:function(){this.dirty=!0,this.delay_timer||this.save_transaction||this.start_save_timer()},start_save_timer:function(){this.cancel_delay(),this.delay_timer=s.later(this.delay,this,this.save_changes)},cancel_delay:function(){this.delay_timer&&!0!==this.delay_timer&&this.delay_timer.cancel(),this.delay_timer=null},save_changes:function(){var e;this.cancel_delay(),this.dirty=!1,this.is_time_nearly_over()?this.stop_autosaving():("undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave(),(e=this.form.all("input[type=submit], button[type=submit]")).setAttribute("type","button"),this.save_transaction=s.io(this.AUTOSAVE_HANDLER,{method:"POST",form:{id:this.form},on:{success:this.save_done,failure:this.save_failed},context:this}),e.setAttribute("type","submit"))},save_done:function(e,t){var i=JSON.parse(t.responseText);"OK"===i.status?("undefined"!=typeof i.timeleft&&M.mod_quiz.timer.updateEndTime(i.timeleft),this.save_transaction=null,this.dirty&&this.start_save_timer(),0<this.savefailures?(s.one(this.SELECTORS.CONNECTION_ERROR).hide(),s.one(this.SELECTORS.CONNECTION_OK).show(),this.savefailures=this.FIRST_SUCCESSFUL_SAVE):this.savefailures===this.FIRST_SUCCESSFUL_SAVE&&(s.one(this.SELECTORS.CONNECTION_OK).hide(),this.savefailures=0)):this.save_failed(e,t)},save_failed:function(){this.save_transaction=null,this.start_save_timer(),this.savefailures=Math.max(1,this.savefailures+1),this.savefailures===this.FAILURES_BEFORE_NOTIFY&&(s.one(this.SELECTORS.CONNECTION_ERROR).show(),s.one(this.SELECTORS.CONNECTION_OK).hide())},is_time_nearly_over:function(){return M.mod_quiz.timer&&M.mod_quiz.timer.endtime&&(new Date).getTime()+2*this.delay>M.mod_quiz.timer.endtime},stop_autosaving:function(){this.cancel_delay(),this.delay_timer=!0,this.save_transaction&&this.save_transaction.abort()}}},"@VERSION@",{requires:["base","node","event","event-valuechange","node-event-delegate","io-form"]});
|
||||
YUI.add("moodle-mod_quiz-autosave",function(n,e){M.mod_quiz=M.mod_quiz||{},M.mod_quiz.autosave={TINYMCE_DETECTION_DELAY:500,TINYMCE_DETECTION_REPEATS:20,WATCH_HIDDEN_DELAY:1e3,FAILURES_BEFORE_NOTIFY:1,FIRST_SUCCESSFUL_SAVE:-1,SELECTORS:{QUIZ_FORM:"#responseform",VALUE_CHANGE_ELEMENTS:'input, textarea, [contenteditable="true"]',CHANGE_ELEMENTS:"input, select",HIDDEN_INPUTS:"input[type=hidden]",CONNECTION_ERROR:"#connection-error",CONNECTION_OK:"#connection-ok"},AUTOSAVE_HANDLER:M.cfg.wwwroot+"/mod/quiz/autosave.ajax.php",delay:12e4,form:null,dirty:!1,delay_timer:null,save_transaction:null,savefailures:0,editor_change_handler:null,hidden_field_values:{},init:function(e){this.form=n.one(this.SELECTORS.QUIZ_FORM),this.form&&(this.delay=1e3*e,this.form.delegate("valuechange",this.value_changed,this.SELECTORS.VALUE_CHANGE_ELEMENTS,this),this.form.delegate("change",this.value_changed,this.SELECTORS.CHANGE_ELEMENTS,this),this.form.on("submit",this.stop_autosaving,this),require(["core_form/events"],function(e){window.addEventListener(e.eventTypes.uploadChanged,this.value_changed.bind(this))}.bind(this)),this.init_tinymce(this.TINYMCE_DETECTION_REPEATS),this.save_hidden_field_values(),this.watch_hidden_fields())},save_hidden_field_values:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name");t&&(this.hidden_field_values[t]=e.get("value"))},this)},watch_hidden_fields:function(){this.detect_hidden_field_changes(),n.later(this.WATCH_HIDDEN_DELAY,this,this.watch_hidden_fields)},detect_hidden_field_changes:function(){this.form.all(this.SELECTORS.HIDDEN_INPUTS).each(function(e){var t=e.get("name"),i=e.get("value");t&&(t in this.hidden_field_values&&i===this.hidden_field_values[t]||(this.hidden_field_values[t]=i,this.value_changed({target:e})))},this)},init_tinymce:function(e){var t;"undefined"!=typeof window.tinyMCE?(this.editor_change_handler=n.bind(this.editor_changed,this),window.tinyMCE.onAddEditor?window.tinyMCE.onAddEditor.add(n.bind(this.init_tinymce_editor,this)):window.tinyMCE.on&&(t=this.start_save_timer_if_necessary.bind(this),window.tinyMCE.on("AddEditor",function(e){e.editor.on("Change Undo Redo keydown",t)}),window.tinyMCE.get().forEach(function(e){e.on("Change Undo Redo keydown",t)}))):0<e&&n.later(this.TINYMCE_DETECTION_DELAY,this,this.init_tinymce,[e-1])},init_tinymce_editor:function(e,t){t.onChange.add(this.editor_change_handler),t.onRedo.add(this.editor_change_handler),t.onUndo.add(this.editor_change_handler),t.onKeyDown.add(this.editor_change_handler)},value_changed:function(e){var t=e.target.getAttribute("name");"thispage"===t||"scrollpos"===t||t&&t.match(/_:flagged$/)||(t=t||"#"+e.target.getAttribute("id"),this.start_save_timer_if_necessary())},editor_changed:function(e){this.start_save_timer_if_necessary()},start_save_timer_if_necessary:function(){this.dirty=!0,this.delay_timer||this.save_transaction||this.start_save_timer()},start_save_timer:function(){this.cancel_delay(),this.delay_timer=n.later(this.delay,this,this.save_changes)},cancel_delay:function(){this.delay_timer&&!0!==this.delay_timer&&this.delay_timer.cancel(),this.delay_timer=null},save_changes:function(){var e;this.cancel_delay(),this.dirty=!1,this.is_time_nearly_over()?this.stop_autosaving():("undefined"!=typeof window.tinyMCE&&window.tinyMCE.triggerSave(),(e=this.form.all("input[type=submit], button[type=submit]")).setAttribute("type","button"),this.save_transaction=n.io(this.AUTOSAVE_HANDLER,{method:"POST",form:{id:this.form},on:{success:this.save_done,failure:this.save_failed},context:this}),e.setAttribute("type","submit"))},save_done:function(e,t){var i=JSON.parse(t.responseText);"OK"===i.status?("undefined"!=typeof i.timeleft&&M.mod_quiz.timer.updateEndTime(i.timeleft),this.save_transaction=null,this.dirty&&this.start_save_timer(),0<this.savefailures?(n.one(this.SELECTORS.CONNECTION_ERROR).hide(),n.one(this.SELECTORS.CONNECTION_OK).show(),this.savefailures=this.FIRST_SUCCESSFUL_SAVE):this.savefailures===this.FIRST_SUCCESSFUL_SAVE&&(n.one(this.SELECTORS.CONNECTION_OK).hide(),this.savefailures=0)):this.save_failed(e,t)},save_failed:function(){this.save_transaction=null,this.start_save_timer(),this.savefailures=Math.max(1,this.savefailures+1),this.savefailures===this.FAILURES_BEFORE_NOTIFY&&(n.one(this.SELECTORS.CONNECTION_ERROR).show(),n.one(this.SELECTORS.CONNECTION_OK).hide())},is_time_nearly_over:function(){return M.mod_quiz.timer&&M.mod_quiz.timer.endtime&&(new Date).getTime()+2*this.delay>M.mod_quiz.timer.endtime},stop_autosaving:function(){this.cancel_delay(),this.delay_timer=!0,this.save_transaction&&this.save_transaction.abort()}}},"@VERSION@",{requires:["base","node","event","event-valuechange","node-event-delegate","io-form"]});
|
||||
@@ -271,7 +271,12 @@ M.mod_quiz.autosave = {
|
||||
window.tinyMCE.on('AddEditor', function(event) {
|
||||
event.editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
// One or more editors might already have been added, so we have to attach
|
||||
// the event handlers to these as well.
|
||||
window.tinyMCE.get().forEach(function(editor) {
|
||||
editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+6
-1
@@ -272,7 +272,12 @@ M.mod_quiz.autosave = {
|
||||
window.tinyMCE.on('AddEditor', function(event) {
|
||||
event.editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
// One or more editors might already have been added, so we have to attach
|
||||
// the event handlers to these as well.
|
||||
window.tinyMCE.get().forEach(function(editor) {
|
||||
editor.on('Change Undo Redo keydown', startSaveTimer);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -228,6 +228,7 @@ function resource_get_coursemodule_info($coursemodule) {
|
||||
$mainfile = reset($files);
|
||||
$resource->mainfile = $mainfile->get_filename();
|
||||
$info->icon = file_file_icon($mainfile);
|
||||
$info->customdata['filtericon'] = true;
|
||||
}
|
||||
|
||||
$display = resource_get_final_display_type($resource);
|
||||
|
||||
+2
-2
@@ -1497,10 +1497,10 @@ abstract class repository implements cacheable_object {
|
||||
//if the context is SYSTEM, so we call it from administration page
|
||||
$admin = ($context->id == SYSCONTEXTID) ? true : false;
|
||||
if ($admin) {
|
||||
$baseurl = new moodle_url('/'.$CFG->admin.'/repositoryinstance.php', array('sesskey'=>sesskey()));
|
||||
$baseurl = new moodle_url('/admin/repositoryinstance.php');
|
||||
$output .= $OUTPUT->heading(get_string('siteinstances', 'repository'));
|
||||
} else {
|
||||
$baseurl = new moodle_url('/repository/manage_instances.php', array('contextid'=>$context->id, 'sesskey'=>sesskey()));
|
||||
$baseurl = new moodle_url('/repository/manage_instances.php', ['contextid' => $context->id]);
|
||||
}
|
||||
|
||||
$namestr = get_string('name');
|
||||
|
||||
@@ -37,9 +37,7 @@ $contextid = optional_param('contextid', 0, PARAM_INT);
|
||||
$usercourseid = optional_param('usercourseid', SITEID, PARAM_INT); // Extra: used for user context only
|
||||
|
||||
$url = new moodle_url('/repository/manage_instances.php');
|
||||
|
||||
$baseurl = new moodle_url('/repository/manage_instances.php');
|
||||
$baseurl->param('sesskey', sesskey());
|
||||
|
||||
if ($edit){
|
||||
$url->param('edit', $edit);
|
||||
@@ -168,9 +166,6 @@ if (!empty($edit) || !empty($new)) {
|
||||
exit;
|
||||
|
||||
} else if ($fromform = $mform->get_data()){
|
||||
if (!confirm_sesskey()) {
|
||||
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
|
||||
}
|
||||
if ($edit) {
|
||||
$settings = array();
|
||||
$settings['name'] = $fromform->name;
|
||||
@@ -199,9 +194,7 @@ if (!empty($edit) || !empty($new)) {
|
||||
}
|
||||
} else if (!empty($delete)) {
|
||||
if ($sure) {
|
||||
if (!confirm_sesskey()) {
|
||||
throw new \moodle_exception('confirmsesskeybad', '', $baseurl);
|
||||
}
|
||||
require_sesskey();
|
||||
if ($instance->delete()) {
|
||||
$deletedstr = get_string('instancedeleted', 'repository');
|
||||
redirect($baseurl, $deletedstr, 3);
|
||||
|
||||
+2
-2
@@ -29,9 +29,9 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2023100901.00; // 20231009 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2023100902.00; // 20231009 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.3.1 (Build: 20231211)'; // Human-friendly version name
|
||||
$release = '4.3.2 (Build: 20231222)'; // Human-friendly version name
|
||||
$branch = '403'; // This version's branch.
|
||||
$maturity = MATURITY_STABLE; // This version's maturity level.
|
||||
|
||||
Reference in New Issue
Block a user