Merge branch 'MOODLE_25_STABLE' into install_25_STABLE
This commit is contained in:
@@ -957,6 +957,8 @@
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="optional">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
|
||||
@@ -62,7 +62,7 @@ class behat_admin extends behat_base {
|
||||
}
|
||||
|
||||
// Search by label.
|
||||
$searchbox = $this->find_field('Search in settings');
|
||||
$searchbox = $this->find_field(get_string('searchinsettings', 'admin'));
|
||||
$searchbox->setValue($label);
|
||||
$submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]');
|
||||
$submitsearch->press();
|
||||
@@ -72,8 +72,12 @@ class behat_admin extends behat_base {
|
||||
// Admin settings does not use the same DOM structure than other moodle forms
|
||||
// but we also need to use lib/behat/form_field/* to deal with the different moodle form elements.
|
||||
$exception = new ElementNotFoundException($this->getSession(), '"' . $label . '" administration setting ');
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$label = $this->getSession()->getSelectorsHandler()->xpathLiteral($label);
|
||||
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(string(.)), '" . $label . "')]/@for]";
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
|
||||
"/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div");
|
||||
@@ -90,7 +94,7 @@ class behat_admin extends behat_base {
|
||||
$field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession());
|
||||
$field->set_value($value);
|
||||
|
||||
$this->find_button('Save changes')->press();
|
||||
$this->find_button(get_string('savechanges'))->press();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ Feature: Display extended course names
|
||||
And I should not see "C_shortname Course fullname"
|
||||
|
||||
Scenario: Courses list with extended course names
|
||||
Given I click on "Courses" "link" in the "//div[@id='settingsnav']//descendant::li[contains(concat(' ', @class, ' '), ' type_setting ')][not(contains(., 'Site administration'))][contains(., 'Appearance')]" "xpath_element"
|
||||
Given I click on "Courses" "link" in the "//div[@id='settingsnav']/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' type_setting ')][not(contains(., 'Site administration'))][contains(., 'Appearance')]" "xpath_element"
|
||||
And I check "Display extended course names"
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
|
||||
@@ -142,6 +142,9 @@ foreach ($vars as $var) {
|
||||
$CFG->{$var} = $CFG->{'behat_' . $var};
|
||||
}
|
||||
|
||||
// Clean $CFG extra values before performing any action.
|
||||
behat_clean_init_config();
|
||||
|
||||
$CFG->noemailever = true;
|
||||
$CFG->passwordsaltmain = 'moodle';
|
||||
|
||||
|
||||
@@ -41,6 +41,5 @@ $string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected o
|
||||
$string['viewsteps'] = 'Filter';
|
||||
$string['wheninfo'] = 'When. Actions that provokes an event';
|
||||
$string['wrongbehatsetup'] = 'Something is wrong with behat setup, ensure:<ul>
|
||||
<li>You ran "curl http://getcomposer.org/installer | php"</li>
|
||||
<li>You ran "php composer.phar install --dev"</li>
|
||||
<li>You ran "php admin/tool/behat/cli/init.php" from your moodle root directory</li>
|
||||
<li>vendor/bin/behat file has execution permissions</li></ul>';
|
||||
|
||||
@@ -37,7 +37,7 @@ Feature: Page contents assertions
|
||||
And I follow "Course 1"
|
||||
When I click on "Move this to the dock" "button" in the ".block_settings" "css_element"
|
||||
Then I should not see "Question bank"
|
||||
And I click on "//div[@id='dock']/descendant::*[contains(., 'Administration')]/h2" "xpath_element"
|
||||
And I click on "//div[@id='dock']/descendant::h2[normalize-space(.)='Administration']" "xpath_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Locators inside specific DOM nodes using XPath
|
||||
@@ -45,5 +45,5 @@ Feature: Page contents assertions
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
When I click on "Move this to the dock" "button" in the "//*[contains(concat(' ', normalize-space(@class), ' '), ' block_settings ')]" "xpath_element"
|
||||
When I click on "Move this to the dock" "button" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' block_settings ')]" "xpath_element"
|
||||
Then I should not see "Turn editing on"
|
||||
|
||||
@@ -30,17 +30,17 @@ Feature: Set up contextual data for tests
|
||||
Then I should see "Course 1"
|
||||
And I should see "Course 2"
|
||||
And I should see "Course 3"
|
||||
When I go to the courses management page
|
||||
And I go to the courses management page
|
||||
And I follow "Cat 1"
|
||||
Then I should see "Cat 2"
|
||||
And I should see "Cat 2"
|
||||
And I should see "Cat 3"
|
||||
When I follow "Cat 3"
|
||||
Then I should see "Course 1"
|
||||
And I follow "Cat 3"
|
||||
And I should see "Course 1"
|
||||
And I should see "Course 2"
|
||||
When I select "Cat 2" from "Course categories:"
|
||||
Then I should see "No courses in this category"
|
||||
When I select "Miscellaneous" from "Course categories:"
|
||||
Then I should see "Course 3"
|
||||
And I select "Cat 1 / Cat 2" from "Course categories:"
|
||||
And I should see "No courses in this category"
|
||||
And I select "Miscellaneous" from "Course categories:"
|
||||
And I should see "Course 3"
|
||||
|
||||
@javascript
|
||||
Scenario: Add a bunch of groups and groupings
|
||||
|
||||
@@ -74,12 +74,11 @@ if (isset($script)) {
|
||||
$prevreferences = $DB->get_records_select('profiling',
|
||||
'url = ? AND runreference = 1 AND timecreated < ?',
|
||||
array($run->url, $run->timecreated),
|
||||
'timecreated DESC', 'runid', 0, 1);
|
||||
$prevrunid = $prevreferences ? reset($prevreferences)->runid : false;
|
||||
'timecreated DESC', 'runid, runcomment, timecreated', 0, 10);
|
||||
echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
|
||||
$header = get_string('lastrunof', 'tool_profiling', $script);
|
||||
echo $OUTPUT->heading($header);
|
||||
$table = profiling_print_run($run, $prevrunid);
|
||||
$table = profiling_print_run($run, $prevreferences);
|
||||
echo $table;
|
||||
echo $OUTPUT->box_end();
|
||||
|
||||
@@ -126,12 +125,11 @@ if (isset($script)) {
|
||||
$prevreferences = $DB->get_records_select('profiling',
|
||||
'url = ? AND runreference = 1 AND timecreated < ?',
|
||||
array($run->url, $run->timecreated),
|
||||
'timecreated DESC', 'runid', 0, 1);
|
||||
$prevrunid = $prevreferences ? reset($prevreferences)->runid : false;
|
||||
'timecreated DESC', 'runid, runcomment, timecreated', 0, 10);
|
||||
echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter');
|
||||
$header = get_string('summaryof', 'tool_profiling', $run->url);
|
||||
echo $OUTPUT->heading($header);
|
||||
$table = profiling_print_run($run, $prevrunid);
|
||||
$table = profiling_print_run($run, $prevreferences);
|
||||
echo $table;
|
||||
echo $OUTPUT->box_end();
|
||||
|
||||
|
||||
@@ -51,5 +51,5 @@ $string['referencerun'] = 'Reference run/comment';
|
||||
$string['runid'] = 'Run ID';
|
||||
$string['summaryof'] = 'Summary of {$a}';
|
||||
$string['viewdetails'] = 'View profiling details';
|
||||
$string['viewdiff'] = 'View profiling differences with last reference run';
|
||||
$string['viewdiff'] = 'View profiling differences with:';
|
||||
$string['viewdiffdetails'] = 'View profiling diff details';
|
||||
|
||||
@@ -49,10 +49,10 @@ class behat_auth extends behat_base {
|
||||
public function i_log_in_as($username) {
|
||||
|
||||
return array(new Given('I am on homepage'),
|
||||
new Given('I follow "Login"'),
|
||||
new Given('I fill in "Username" with "'.$username.'"'),
|
||||
new Given('I fill in "Password" with "'.$username.'"'),
|
||||
new Given('I press "Login"')
|
||||
new Given('I follow "' . get_string('login') . '"'),
|
||||
new Given('I fill in "' . get_string('username') . '" with "' . $this->escape($username) . '"'),
|
||||
new Given('I fill in "' . get_string('password') . '" with "'. $this->escape($username) . '"'),
|
||||
new Given('I press "' . get_string('login') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class behat_auth extends behat_base {
|
||||
* @Given /^I log out$/
|
||||
*/
|
||||
public function i_log_out() {
|
||||
return new When('I follow "Logout"');
|
||||
return new When('I follow "' . get_string('logout') . '"');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -24,16 +23,32 @@
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
class backup_files_edit_form extends moodleform {
|
||||
function definition() {
|
||||
|
||||
/**
|
||||
* Form definition.
|
||||
*/
|
||||
public function definition() {
|
||||
$mform =& $this->_form;
|
||||
$contextid = $this->_customdata['contextid'];
|
||||
$options = array('subdirs'=>0, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL | FILE_REFERENCE);
|
||||
|
||||
$options = array('subdirs' => 0, 'maxfiles' => -1, 'accepted_types' => '*', 'return_types' => FILE_INTERNAL | FILE_REFERENCE);
|
||||
|
||||
$mform->addElement('filemanager', 'files_filemanager', get_string('files'), null, $options);
|
||||
|
||||
$mform->addElement('hidden', 'contextid', $this->_customdata['contextid']);
|
||||
$mform->setType('contextid', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'currentcontext', $this->_customdata['currentcontext']);
|
||||
$mform->setType('currentcontext', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'filearea', $this->_customdata['filearea']);
|
||||
$mform->setType('filearea', PARAM_AREA);
|
||||
|
||||
$mform->addElement('hidden', 'component', $this->_customdata['component']);
|
||||
$mform->setType('component', PARAM_COMPONENT);
|
||||
|
||||
$mform->addElement('hidden', 'returnurl', $this->_customdata['returnurl']);
|
||||
$mform->setType('returnurl', PARAM_URL);
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
$this->set_data($this->_customdata['data']);
|
||||
}
|
||||
|
||||
@@ -614,13 +614,20 @@ abstract class restore_dbops {
|
||||
} else {
|
||||
self::set_backup_ids_record($restoreid, 'question_category', $category->id, $matchcat->id, $targetcontext->id);
|
||||
$questions = self::restore_get_questions($restoreid, $category->id);
|
||||
|
||||
// Collect all the questions for this category into memory so we only talk to the DB once.
|
||||
$questioncache = $DB->get_records_sql_menu("SELECT ".$DB->sql_concat('stamp', "' '", 'version').", id
|
||||
FROM {question}
|
||||
WHERE category = ?", array($matchcat->id));
|
||||
|
||||
foreach ($questions as $question) {
|
||||
$matchq = $DB->get_record('question', array(
|
||||
'category' => $matchcat->id,
|
||||
'stamp' => $question->stamp,
|
||||
'version' => $question->version));
|
||||
if (isset($questioncache[$question->stamp." ".$question->version])) {
|
||||
$matchqid = $questioncache[$question->stamp." ".$question->version];
|
||||
} else {
|
||||
$matchqid = false;
|
||||
}
|
||||
// 5a) No match, check if user can add q
|
||||
if (!$matchq) {
|
||||
if (!$matchqid) {
|
||||
// 6a) User can, mark the q to be created
|
||||
if ($canadd) {
|
||||
// Nothing to mark, newitemid means create
|
||||
@@ -645,7 +652,7 @@ abstract class restore_dbops {
|
||||
|
||||
// 5b) Match, mark q to be mapped
|
||||
} else {
|
||||
self::set_backup_ids_record($restoreid, 'question', $question->id, $matchq->id);
|
||||
self::set_backup_ids_record($restoreid, 'question', $question->id, $matchqid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ Feature: Backup Moodle courses
|
||||
And I should not see "Section 3"
|
||||
And I press "Continue"
|
||||
And I click on "Continue" "button" in the ".bcs-current-course" "css_element"
|
||||
And I click on "//div[contains(concat(' ', @class, ' '), ' fitem ')][contains(., 'Include calendar events')]/descendant::img" "xpath_element"
|
||||
And I click on "setting_root_logs" "checkbox" in the "//div[contains(@class, 'fitem')][contains(., 'Include course logs')]" "xpath_element"
|
||||
And "//div[contains(concat(' ', normalize-space(@class), ' '), ' fitem ')][contains(., 'Include calendar events')]/descendant::img" "xpath_element" should exists
|
||||
And I check "Include course logs"
|
||||
And I press "Cancel"
|
||||
And I click on "Cancel" "button" in the ".confirmation-dialogue" "css_element"
|
||||
|
||||
@@ -61,25 +61,25 @@ class behat_backup extends behat_base {
|
||||
$this->find_link($backupcourse)->click();
|
||||
|
||||
// Click the backup link.
|
||||
$this->find_link('Backup')->click();
|
||||
$this->find_link(get_string('backup'))->click();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('backupstage1action', 'backup'))->press();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('backupstage2action', 'backup'))->press();
|
||||
|
||||
// Confirmation and review, backup filename can also be specified.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Perform backup')->press();
|
||||
$this->find_button(get_string('backupstage4action', 'backup'))->press();
|
||||
|
||||
// Waiting for it to finish.
|
||||
$this->wait(10);
|
||||
|
||||
// Last backup continue button.
|
||||
$this->find_button('Continue')->press();
|
||||
$this->find_button(get_string('backupstage16action', 'backup'))->press();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,36 +105,37 @@ class behat_backup extends behat_base {
|
||||
// Click the course link.
|
||||
$this->find_link($tocourse)->click();
|
||||
|
||||
// Click the backup link.
|
||||
$this->find_link('Import')->click();
|
||||
// Click the import link.
|
||||
$this->find_link(get_string('import'))->click();
|
||||
|
||||
// Select the course.
|
||||
$exception = new ExpectationException('"' . $fromcourse . '" course not found in the list of courses to import from', $this->getSession());
|
||||
|
||||
$fromcourse = str_replace("'", "\'", $fromcourse);
|
||||
$xpath = "//div[contains(concat(' ', @class, ' '), ' ics-results ')]" .
|
||||
"/descendant::tr[contains(., '" . $fromcourse . "')]" .
|
||||
// The argument should be converted to an xpath literal.
|
||||
$fromcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($fromcourse);
|
||||
$xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' ics-results ')]" .
|
||||
"/descendant::tr[contains(., $fromcourse)]" .
|
||||
"/descendant::input[@type='radio']";
|
||||
$radionode = $this->find('xpath', $xpath, $exception);
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
$this->find_button('Continue')->press();
|
||||
$this->find_button(get_string('continue'))->press();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('importbackupstage1action', 'backup'))->press();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('importbackupstage2action', 'backup'))->press();
|
||||
|
||||
// Run it.
|
||||
$this->find_button('Perform import')->press();
|
||||
$this->find_button(get_string('importbackupstage4action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Continue and redirect to 'to' course.
|
||||
$this->find_button('Continue')->press();
|
||||
$this->find_button(get_string('continue'))->press();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,17 +151,20 @@ class behat_backup extends behat_base {
|
||||
// Confirm restore.
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$existingcourse = $this->getSession()->getSelectorsHandler()->xpathLiteral($existingcourse);
|
||||
|
||||
// Selecting the specified course (we can not call behat_forms::select_radio here as is in another behat subcontext).
|
||||
$existingcourse = str_replace("'", "\'", $existingcourse);
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
|
||||
"/descendant::div[@class='restore-course-search']" .
|
||||
"/descendant::tr[contains(., '" . $existingcourse . "')]" .
|
||||
"/descendant::tr[contains(., $existingcourse)]" .
|
||||
"/descendant::input[@type='radio']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore into an existing course section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-existing-course')]/descendant::input[@type='submit'][@value='Continue']");
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-existing-course ')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
|
||||
@@ -181,14 +185,15 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// The first category in the list.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
|
||||
"/descendant::div[@class='restore-course-search']" .
|
||||
"/descendant::input[@type='radio']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore into an existing course section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-new-course')]/descendant::input[@type='submit'][@value='Continue']");
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' bcs-new-course ')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
|
||||
@@ -209,14 +214,14 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// Merge without deleting radio option.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='radio'][@name='target'][@value='1']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore merging section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='Continue']");
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
|
||||
@@ -237,14 +242,14 @@ class behat_backup extends behat_base {
|
||||
$this->select_backup($backupfilename);
|
||||
|
||||
// Delete contents radio option.
|
||||
$radionode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
$radionode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='radio'][@name='target'][@value='0']");
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
|
||||
// Pressing the continue button of the restore merging section.
|
||||
$continuenode = $this->find('xpath', "//div[contains(@class, 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='Continue']");
|
||||
$continuenode = $this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), 'bcs-current-course')]" .
|
||||
"/descendant::input[@type='submit'][@value='" . get_string('continue') . "']");
|
||||
$continuenode->click();
|
||||
$this->wait();
|
||||
|
||||
@@ -263,12 +268,16 @@ class behat_backup extends behat_base {
|
||||
|
||||
// Using xpath as there are other restore links before this one.
|
||||
$exception = new ExpectationException('The "' . $backupfilename . '" backup file can not be found in this page', $this->getSession());
|
||||
$xpath = "//tr[contains(., '" . $backupfilename . "')]/descendant::a[contains(., 'Restore')]";
|
||||
|
||||
// The argument should be converted to an xpath literal.
|
||||
$backupfilename = $this->getSession()->getSelectorsHandler()->xpathLiteral($backupfilename);
|
||||
|
||||
$xpath = "//tr[contains(., $backupfilename)]/descendant::a[contains(., '" . get_string('restore') . "')]";
|
||||
$restorelink = $this->find('xpath', $xpath, $exception);
|
||||
$restorelink->click();
|
||||
|
||||
// Confirm the backup contents.
|
||||
$restore = $this->find_button('Continue')->press();
|
||||
$restore = $this->find_button(get_string('continue'))->press();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,18 +293,18 @@ class behat_backup extends behat_base {
|
||||
|
||||
// Settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('restorestage4action', 'backup'))->press();
|
||||
|
||||
// Schema.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->find_button('Next')->press();
|
||||
$this->find_button(get_string('restorestage8action', 'backup'))->press();
|
||||
|
||||
// Review, no options here.
|
||||
$this->find_button('Perform restore')->press();
|
||||
$this->find_button(get_string('restorestage16action', 'backup'))->press();
|
||||
$this->wait(10);
|
||||
|
||||
// Last restore continue button, redirected to restore course after this.
|
||||
$this->find_button('Continue')->press();
|
||||
$this->find_button(get_string('restorestage32action', 'backup'))->press();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +348,10 @@ class behat_backup extends behat_base {
|
||||
*/
|
||||
protected function wait($timeout = false) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$timeout) {
|
||||
$timeout = self::TIMEOUT;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,18 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
protected $groupedpaths; // Paths we are requesting grouped
|
||||
protected $currentdata; // Where we'll be acummulating data
|
||||
|
||||
/**
|
||||
* Keep cache of parent directory paths for XML parsing.
|
||||
* @var array
|
||||
*/
|
||||
protected $parentcache = array();
|
||||
|
||||
/**
|
||||
* Remaining space for parent directory paths.
|
||||
* @var integer
|
||||
*/
|
||||
protected $parentcacheavailablesize = 2048;
|
||||
|
||||
public function __construct(array $paths = array()) {
|
||||
$this->groupedpaths = array();
|
||||
$this->currentdata = null;
|
||||
@@ -65,7 +77,7 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
$a->child = $found;
|
||||
throw new progressive_parser_exception('xml_grouped_child_found', $a);
|
||||
}
|
||||
$this->groupedpaths[] = $path;
|
||||
$this->groupedpaths[$path] = true;
|
||||
}
|
||||
parent::add_path($path);
|
||||
}
|
||||
@@ -141,7 +153,7 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
}
|
||||
|
||||
protected function path_is_grouped($path) {
|
||||
return in_array($path, $this->groupedpaths);
|
||||
return isset($this->groupedpaths[$path]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,16 +162,41 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
* false if not
|
||||
*/
|
||||
protected function grouped_parent_exists($path) {
|
||||
$parentpath = progressive_parser::dirname($path);
|
||||
$parentpath = $this->get_parent_path($path);
|
||||
|
||||
while ($parentpath != '/') {
|
||||
if ($this->path_is_grouped($parentpath)) {
|
||||
return $parentpath;
|
||||
}
|
||||
$parentpath = progressive_parser::dirname($parentpath);
|
||||
$parentpath = $this->get_parent_path($parentpath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent path using a local cache for performance.
|
||||
*
|
||||
* @param $path string The pathname you wish to obtain the parent name for.
|
||||
* @return string The parent pathname.
|
||||
*/
|
||||
protected function get_parent_path($path) {
|
||||
if (!isset($this->parentcache[$path])) {
|
||||
$this->parentcache[$path] = progressive_parser::dirname($path);
|
||||
$this->parentcacheavailablesize--;
|
||||
if ($this->parentcacheavailablesize < 0) {
|
||||
// Older first is cheaper than LRU. We use 10% as items are grouped together and the large quiz
|
||||
// restore from MDL-40585 used only 600 parent paths. This is an XML heirarchy, so common paths
|
||||
// are grouped near each other. eg; /question_bank/question_category/question/element. After keeping
|
||||
// question_bank paths in the cache when we move to another area and the question_bank cache is not
|
||||
// useful any longer.
|
||||
$this->parentcache = array_slice($this->parentcache, 200, null, true);
|
||||
$this->parentcacheavailablesize += 200;
|
||||
}
|
||||
}
|
||||
return $this->parentcache[$path];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function that will look for any grouped
|
||||
* child for the given path, returning it if found,
|
||||
@@ -167,7 +204,7 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
*/
|
||||
protected function grouped_child_exists($path) {
|
||||
$childpath = $path . '/';
|
||||
foreach ($this->groupedpaths as $groupedpath) {
|
||||
foreach ($this->groupedpaths as $groupedpath => $set) {
|
||||
if (strpos($groupedpath, $childpath) === 0) {
|
||||
return $groupedpath;
|
||||
}
|
||||
|
||||
+14
-1
@@ -2,7 +2,20 @@
|
||||
* Push badges to backpack.
|
||||
*/
|
||||
function addtobackpack(event, args) {
|
||||
OpenBadges.issue([args.assertion], function(errors, successes) { });
|
||||
var badgetable = Y.one('#issued-badge-table');
|
||||
var errordiv = Y.one('#addtobackpack-error');
|
||||
var errortext = M.util.get_string('error:backpackproblem', 'badges');
|
||||
var errorhtml = '<div id="addtobackpack-error" class="box boxaligncenter notifyproblem">' + errortext + '</div>';
|
||||
|
||||
if (typeof OpenBadges !== 'undefined') {
|
||||
OpenBadges.issue([args.assertion], function(errors, successes) { });
|
||||
} else {
|
||||
// Add error div if it doesn't exist yet.
|
||||
if (!errordiv) {
|
||||
var badgerror = Y.Node.create(errorhtml);
|
||||
badgetable.insert(badgerror, 'before');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-4
@@ -56,10 +56,8 @@ if (isloggedin()) {
|
||||
navigation_node::override_active_url($url);
|
||||
}
|
||||
|
||||
// TODO: Better way of pushing badges to Mozilla backpack?
|
||||
if (!empty($CFG->badges_allowexternalbackpack)) {
|
||||
$PAGE->requires->js(new moodle_url('http://backpack.openbadges.org/issuer.js'), true);
|
||||
}
|
||||
// Include JS files for backpack support.
|
||||
badges_setup_backpack_js();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
+2
-5
@@ -90,11 +90,8 @@ $PAGE->set_title($title);
|
||||
$PAGE->set_heading($title);
|
||||
$PAGE->set_pagelayout('mydashboard');
|
||||
|
||||
// TODO: Better way of pushing badges to Mozilla backpack?
|
||||
if (!empty($CFG->badges_allowexternalbackpack)) {
|
||||
$PAGE->requires->js(new moodle_url('http://backpack.openbadges.org/issuer.js'), true);
|
||||
$PAGE->requires->js('/badges/backpack.js', true);
|
||||
}
|
||||
// Include JS files for backpack support.
|
||||
badges_setup_backpack_js();
|
||||
|
||||
$output = $PAGE->get_renderer('core', 'badges');
|
||||
$badges = badges_get_user_badges($USER->id);
|
||||
|
||||
+7
-4
@@ -282,6 +282,7 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
$today = strtotime($today_date);
|
||||
|
||||
$table = new html_table();
|
||||
$table->id = 'issued-badge-table';
|
||||
|
||||
$imagetable = new html_table();
|
||||
$imagetable->attributes = array('class' => 'clearfix badgeissuedimage');
|
||||
@@ -294,11 +295,13 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
$expiration = isset($issued['expires']) ? strtotime($issued['expires']) : $today + 1;
|
||||
if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $today) && badges_user_has_backpack($USER->id)) {
|
||||
$assertion = new moodle_url('/badges/assertion.php', array('b' => $ibadge->hash));
|
||||
$action = new component_action('click', 'addtobackpack', array('assertion' => $assertion->out(false)));
|
||||
$attributes = array(
|
||||
'type' => 'button',
|
||||
'value' => get_string('addtobackpack', 'badges'),
|
||||
'onclick' => 'OpenBadges.issue(["' . $assertion->out(false) . '"], function(errors, successes) { })');
|
||||
'type' => 'button',
|
||||
'id' => 'addbutton',
|
||||
'value' => get_string('addtobackpack', 'badges'));
|
||||
$tobackpack = html_writer::tag('input', '', $attributes);
|
||||
$this->output->add_action_handler($action, 'addbutton');
|
||||
$imagetable->data[] = array($tobackpack);
|
||||
}
|
||||
}
|
||||
@@ -459,7 +462,7 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
get_string('downloadall'), 'POST', array('class' => 'activatebadge'));
|
||||
|
||||
// Local badges.
|
||||
$localhtml = html_writer::start_tag('fieldset', array('class' => 'generalbox'));
|
||||
$localhtml = html_writer::start_tag('fieldset', array('id' => 'issued-badge-table', 'class' => 'generalbox'));
|
||||
$localhtml .= html_writer::tag('legend',
|
||||
$this->output->heading_with_help(get_string('localbadges', 'badges', $SITE->fullname), 'localbadgesh', 'badges'));
|
||||
if ($badges->badges) {
|
||||
|
||||
@@ -63,7 +63,7 @@ class behat_block_comments extends behat_base {
|
||||
$commentstextarea = $this->find('css', '.comment-area textarea', $exception);
|
||||
$commentstextarea->setValue($comment);
|
||||
|
||||
$this->find_link('Save comment')->click();
|
||||
$this->find_link(get_string('savecomment'))->click();
|
||||
|
||||
// Wait for the AJAX request.
|
||||
$this->getSession()->wait(4 * 1000, false);
|
||||
@@ -91,8 +91,11 @@ class behat_block_comments extends behat_base {
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), '"' . $comment . '" comment ');
|
||||
|
||||
$commentxpath = "//div[contains(concat(' ', @class, ' '), ' block_comments ')]" .
|
||||
"/descendant::div[@class='comment-message'][contains(., '" . $comment . "')]";
|
||||
// Using xpath liternal to avoid possible problems with comments containing quotes.
|
||||
$commentliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($comment);
|
||||
|
||||
$commentxpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' block_comments ')]" .
|
||||
"/descendant::div[@class='comment-message'][contains(., $commentliteral)]";
|
||||
$commentnode = $this->find('xpath', $commentxpath, $exception);
|
||||
|
||||
// Click on delete icon.
|
||||
@@ -101,7 +104,7 @@ class behat_block_comments extends behat_base {
|
||||
$deleteicon->click();
|
||||
|
||||
// Yes confirm.
|
||||
$confirmnode = $this->find('xpath', "//div[@class='comment-delete-confirm']/descendant::a[contains(., 'Yes')]");
|
||||
$confirmnode = $this->find('xpath', "//div[@class='comment-delete-confirm']/descendant::a[contains(., '" . get_string('yes') . "')]");
|
||||
$confirmnode->click();
|
||||
|
||||
// Wait for the AJAX request.
|
||||
|
||||
@@ -103,10 +103,10 @@ class block_course_overview_renderer extends plugin_renderer_base {
|
||||
|
||||
// No need to pass title through s() here as it will be done automatically by html_writer.
|
||||
$attributes = array('title' => $course->fullname);
|
||||
if (empty($course->visible)) {
|
||||
$attributes['class'] = 'dimmed';
|
||||
}
|
||||
if ($course->id > 0) {
|
||||
if (empty($course->visible)) {
|
||||
$attributes['class'] = 'dimmed';
|
||||
}
|
||||
$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
|
||||
$coursefullname = format_string($course->fullname, true, $course->id);
|
||||
$link = html_writer::link($courseurl, $coursefullname, $attributes);
|
||||
|
||||
@@ -46,13 +46,13 @@ class behat_blocks extends behat_base {
|
||||
* @param string $blockname
|
||||
*/
|
||||
public function i_add_the_block($blockname) {
|
||||
$steps = new Given('I select "' . $blockname . '" from "bui_addblock"');
|
||||
$steps = new Given('I select "' . $this->escape($blockname) . '" from "bui_addblock"');
|
||||
|
||||
// If we are running without javascript we need to submit the form.
|
||||
if (!$this->running_javascript()) {
|
||||
$steps = array(
|
||||
$steps,
|
||||
new Given('I click on "Go" "button" in the "#add_block" "css_element"')
|
||||
new Given('I click on "' . get_string('go') . '" "button" in the "#add_block" "css_element"')
|
||||
);
|
||||
}
|
||||
return $steps;
|
||||
|
||||
@@ -32,4 +32,4 @@ Feature: Add and configure blocks throughout the site
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
# The first block matching the pattern should be top-left block
|
||||
And I should see "Comments" in the "//*[@id='region-pre']/descendant::div[contains(concat(' ', @class, ' '), ' block ')]" "xpath_element"
|
||||
And I should see "Comments" in the "//*[@id='region-pre']/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]" "xpath_element"
|
||||
|
||||
+2
-1
@@ -49,7 +49,8 @@ class cachestore_memcache_addinstance_form extends cachestore_addinstance_form {
|
||||
$form->addElement('text', 'prefix', get_string('prefix', 'cachestore_memcache'),
|
||||
array('maxlength' => 5, 'size' => 5));
|
||||
$form->addHelpButton('prefix', 'prefix', 'cachestore_memcache');
|
||||
$form->setType('prefix', PARAM_ALPHAEXT);
|
||||
$form->setType('prefix', PARAM_TEXT); // We set to text but we have a rule to limit to alphanumext.
|
||||
$form->setDefault('prefix', 'mdl_');
|
||||
$form->addRule('prefix', get_string('prefixinvalid', 'cachestore_memcache'), 'regex', '#^[a-zA-Z0-9\-_]+$#');
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@ $string['prefix'] = 'Key prefix';
|
||||
$string['prefix_help'] = 'This prefix is used for all key names on the memcache server.
|
||||
* If you only have one Moodle instance using this server, you can leave this value default.
|
||||
* Due to key length restrictions, a maximum of 5 characters is permitted.';
|
||||
$string['prefixinvalid'] = 'Invalid prefix. You can only use a-z A-Z 0-9-_.';
|
||||
$string['servers'] = 'Servers';
|
||||
$string['servers_help'] = 'This sets the servers that should be utilised by this memcache adapter.
|
||||
Servers should be defined one per line and consist of a server address and optionally a port and weight.
|
||||
|
||||
Vendored
+1
-1
@@ -404,7 +404,7 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
|
||||
* Generates an instance of the cache store that can be used for testing.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return false
|
||||
* @return cachestore_memcache|false
|
||||
*/
|
||||
public static function initialise_test_instance(cache_definition $definition) {
|
||||
if (!self::are_requirements_met()) {
|
||||
|
||||
+32
-1
@@ -59,4 +59,35 @@ class cachestore_memcache_test extends cachestore_tests {
|
||||
protected function get_class_name() {
|
||||
return 'cachestore_memcache';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the valid keys to ensure they work.
|
||||
*/
|
||||
public function test_valid_keys() {
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcache', 'phpunit_test');
|
||||
$instance = cachestore_memcache::initialise_test_instance($definition);
|
||||
|
||||
if (!$instance) { // Something prevented memcache store to be inited (extension, TEST_CACHESTORE_MEMCACHE_TESTSERVERS...).
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$keys = array(
|
||||
// Alphanumeric.
|
||||
'abc', 'ABC', '123', 'aB1', '1aB',
|
||||
// Hyphens.
|
||||
'a-1', '1-a', '-a1', 'a1-',
|
||||
// Underscores.
|
||||
'a_1', '1_a', '_a1', 'a1_'
|
||||
);
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->set($key, $key), "Failed to set key `$key`");
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
$this->assertEquals($key, $instance->get($key), "Failed to get key `$key`");
|
||||
}
|
||||
$values = $instance->get_many($keys);
|
||||
foreach ($values as $key => $value) {
|
||||
$this->assertEquals($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -57,11 +57,12 @@ class cachestore_memcached_addinstance_form extends cachestore_addinstance_form
|
||||
$form->addElement('select', 'serialiser', get_string('useserialiser', 'cachestore_memcached'), $serialiseroptions);
|
||||
$form->addHelpButton('serialiser', 'useserialiser', 'cachestore_memcached');
|
||||
$form->setDefault('serialiser', Memcached::SERIALIZER_PHP);
|
||||
$form->setType('serialiser', PARAM_NUMBER);
|
||||
$form->setType('serialiser', PARAM_INT);
|
||||
|
||||
$form->addElement('text', 'prefix', get_string('prefix', 'cachestore_memcached'), array('size' => 16));
|
||||
$form->setType('prefix', PARAM_ALPHANUM);
|
||||
$form->setType('prefix', PARAM_TEXT); // We set to text but we have a rule to limit to alphanumext.
|
||||
$form->addHelpButton('prefix', 'prefix', 'cachestore_memcached');
|
||||
$form->addRule('prefix', get_string('prefixinvalid', 'cachestore_memcached'), 'regex', '#^[a-zA-Z0-9\-_]+$#');
|
||||
|
||||
$hashoptions = cachestore_memcached::config_get_hash_options();
|
||||
$form->addElement('select', 'hash', get_string('hash', 'cachestore_memcached'), $hashoptions);
|
||||
@@ -74,4 +75,4 @@ class cachestore_memcached_addinstance_form extends cachestore_addinstance_form
|
||||
$form->setDefault('bufferwrites', 0);
|
||||
$form->setType('bufferwrites', PARAM_BOOL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ $string['hash_murmur'] = 'Murmur';
|
||||
$string['pluginname'] = 'Memcached';
|
||||
$string['prefix'] = 'Prefix key';
|
||||
$string['prefix_help'] = 'This can be used to create a "domain" for your item keys allowing you to create multiple memcached stores on a single memcached installation. It cannot be longer than 16 characters in order to ensure key length issues are not encountered.';
|
||||
$string['prefixinvalid'] = 'Invalid prefix. You can only use a-z A-Z 0-9-_.';
|
||||
$string['serialiser_igbinary'] = 'The igbinary serializer.';
|
||||
$string['serialiser_json'] = 'The JSON serializer.';
|
||||
$string['serialiser_php'] = 'The default PHP serializer.';
|
||||
|
||||
Vendored
+2
-2
@@ -339,7 +339,7 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
$options[Memcached::SERIALIZER_JSON] = get_string('serialiser_json', 'cachestore_memcached');
|
||||
}
|
||||
if (Memcached::HAVE_IGBINARY) {
|
||||
$options[Memcached::SERIALIZER_IGBINARY] = get_string('serialiser_php', 'cachestore_memcached');
|
||||
$options[Memcached::SERIALIZER_IGBINARY] = get_string('serialiser_igbinary', 'cachestore_memcached');
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
@@ -444,7 +444,7 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
|
||||
* Generates an instance of the cache store that can be used for testing.
|
||||
*
|
||||
* @param cache_definition $definition
|
||||
* @return false
|
||||
* @return cachestore_memcached|false
|
||||
*/
|
||||
public static function initialise_test_instance(cache_definition $definition) {
|
||||
|
||||
|
||||
+32
-1
@@ -59,4 +59,35 @@ class cachestore_memcached_test extends cachestore_tests {
|
||||
protected function get_class_name() {
|
||||
return 'cachestore_memcached';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the valid keys to ensure they work.
|
||||
*/
|
||||
public function test_valid_keys() {
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, 'cachestore_memcached', 'phpunit_test');
|
||||
$instance = cachestore_memcached::initialise_test_instance($definition);
|
||||
|
||||
if (!$instance) { // Something prevented memcached store to be inited (extension, TEST_CACHESTORE_MEMCACHED_TESTSERVERS...).
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
|
||||
$keys = array(
|
||||
// Alphanumeric.
|
||||
'abc', 'ABC', '123', 'aB1', '1aB',
|
||||
// Hyphens.
|
||||
'a-1', '1-a', '-a1', 'a1-',
|
||||
// Underscores.
|
||||
'a_1', '1_a', '_a1', 'a1_'
|
||||
);
|
||||
foreach ($keys as $key) {
|
||||
$this->assertTrue($instance->set($key, $key), "Failed to set key `$key`");
|
||||
}
|
||||
foreach ($keys as $key) {
|
||||
$this->assertEquals($key, $instance->get($key), "Failed to get key `$key`");
|
||||
}
|
||||
$values = $instance->get_many($keys);
|
||||
foreach ($values as $key => $value) {
|
||||
$this->assertEquals($key, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -62,7 +62,7 @@ abstract class cachestore_tests extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
if ($modes & cache_store::MODE_SESSION) {
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, $class, 'phpunit_test');
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_SESSION, $class, 'phpunit_test');
|
||||
$instance = $class::initialise_test_instance($definition);
|
||||
if (!$instance) {
|
||||
$this->markTestSkipped('Could not test '.$class.'. No test instance configured for session caches.');
|
||||
@@ -71,7 +71,7 @@ abstract class cachestore_tests extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
if ($modes & cache_store::MODE_REQUEST) {
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_APPLICATION, $class, 'phpunit_test');
|
||||
$definition = cache_definition::load_adhoc(cache_store::MODE_REQUEST, $class, 'phpunit_test');
|
||||
$instance = $class::initialise_test_instance($definition);
|
||||
if (!$instance) {
|
||||
$this->markTestSkipped('Could not test '.$class.'. No test instance configured for request caches.');
|
||||
|
||||
@@ -54,10 +54,10 @@ class behat_cohort extends behat_base {
|
||||
$userid = $DB->get_field('user', 'id', array('username' => $username));
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "Assign" "link" in the "//table[@id=\'cohorts\']//tr[contains(., \'' . $cohortidnumber . '\')]" "xpath_element"'),
|
||||
new Given('I select "' . $userid . '" from "Potential users"'),
|
||||
new Given('I press "Add"'),
|
||||
new Given('I press "Back to cohorts"')
|
||||
new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" table row'),
|
||||
new Given('I select "' . $userid . '" from "' . get_string('potusers', 'cohort') . '"'),
|
||||
new Given('I press "' . get_string('add') . '"'),
|
||||
new Given('I press "' . get_string('backtocohorts', 'cohort') . '"')
|
||||
);
|
||||
|
||||
// If we are not in the cohorts management we should move there before anything else.
|
||||
@@ -65,11 +65,11 @@ class behat_cohort extends behat_base {
|
||||
$steps = array_merge(
|
||||
array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I collapse "Front page settings" node'),
|
||||
new Given('I expand "Site administration" node'),
|
||||
new Given('I expand "Users" node'),
|
||||
new Given('I expand "Accounts" node'),
|
||||
new Given('I follow "Cohorts"')
|
||||
new Given('I collapse "' . get_string('frontpagesettings', 'admin') . '" node'),
|
||||
new Given('I expand "' . get_string('administrationsite') . '" node'),
|
||||
new Given('I expand "' . get_string('users', 'admin') . '" node'),
|
||||
new Given('I expand "' . get_string('accounts', 'admin') . '" node'),
|
||||
new Given('I follow "' . get_string('cohorts', 'cohort') . '"')
|
||||
),
|
||||
$steps
|
||||
);
|
||||
|
||||
@@ -32,11 +32,11 @@ Feature: Upload users to a cohort
|
||||
And I press "Upload users"
|
||||
And I press "Continue"
|
||||
And I follow "Cohorts"
|
||||
And I click on "Assign" "link" in the "//table[@id='cohorts']//tr[contains(., 'Cohort 1')]" "xpath_element"
|
||||
And I click on "Assign" "link" in the "Cohort 1" table row
|
||||
Then the "Current users" select box should contain "Tom Jones (tomjones@example.com)"
|
||||
And the "Current users" select box should contain "Bob Jones (bobjones@example.com)"
|
||||
And I press "Back to cohorts"
|
||||
And I click on "Assign" "link" in the "//table[@id='cohorts']//tr[contains(., 'Cohort 2')]" "xpath_element"
|
||||
And I click on "Assign" "link" in the "Cohort 2" table row
|
||||
And the "Current users" select box should contain "Mary Smith (marysmith@example.com)"
|
||||
And the "Current users" select box should contain "Alice Smith (alicesmith@example.com)"
|
||||
And I am on homepage
|
||||
|
||||
@@ -50,12 +50,13 @@ class behat_completion extends behat_base {
|
||||
public function user_has_completed_activity($userfullname, $activityname) {
|
||||
|
||||
// Will throw an exception if the element can not be hovered.
|
||||
$titleliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($userfullname . ", " . $activityname . ": Completed");
|
||||
$xpath = "//table[@id='completion-progress']" .
|
||||
"/descendant::img[contains(@title, '" . $userfullname . ", " . $activityname . ": Completed')]";
|
||||
"/descendant::img[contains(@title, $titleliteral)]";
|
||||
|
||||
return array(
|
||||
new Given('I go to the current course activity completion report'),
|
||||
new Given('I hover "' . $xpath . '" "xpath_element"')
|
||||
new Given('I hover "' . $this->escape($xpath) . '" "xpath_element"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -68,11 +69,13 @@ class behat_completion extends behat_base {
|
||||
*/
|
||||
public function user_has_not_completed_activity($userfullname, $activityname) {
|
||||
|
||||
// Will throw an exception if the element can not be hovered.
|
||||
$titleliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($userfullname . ", " . $activityname . ": Not completed");
|
||||
$xpath = "//table[@id='completion-progress']" .
|
||||
"/descendant::img[contains(@title, '" . $userfullname . ", " . $activityname . ": Not completed')]";
|
||||
"/descendant::img[contains(@title, $titleliteral)]";
|
||||
return array(
|
||||
new Given('I go to the current course activity completion report'),
|
||||
new Given('I hover "' . $xpath . '" "xpath_element"')
|
||||
new Given('I hover "' . $this->escape($xpath) . '" "xpath_element"')
|
||||
);
|
||||
|
||||
return $steps;
|
||||
@@ -89,15 +92,15 @@ class behat_completion extends behat_base {
|
||||
|
||||
// Expand reports node if we can't see the link.
|
||||
try {
|
||||
$this->find('xpath', "//*[@id='settingsnav']" .
|
||||
$this->find('xpath', "//div[@id='settingsnav']" .
|
||||
"/descendant::li" .
|
||||
"/descendant::li[not(contains(@class,'collapsed'))]" .
|
||||
"/descendant::p[contains(., 'Activity completion')]");
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/descendant::p[contains(., '" . get_string('pluginname', 'report_progress') . "')]");
|
||||
} catch (ElementNotFoundException $e) {
|
||||
$steps[] = new Given('I expand "Reports" node');
|
||||
$steps[] = new Given('I expand "' . get_string('reports') . '" node');
|
||||
}
|
||||
|
||||
$steps[] = new Given('I follow "Activity completion"');
|
||||
$steps[] = new Given('I follow "' . get_string('pluginname', 'report_progress') . '"');
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
+2
-3
@@ -670,7 +670,6 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
|
||||
//Accessibility: for files get description via icon, this is very ugly hack!
|
||||
$instancename = $mod->get_formatted_name();
|
||||
$altname = '';
|
||||
$altname = $mod->modfullname;
|
||||
// Avoid unnecessary duplication: if e.g. a forum name already
|
||||
// includes the word forum (or Forum, etc) then it is unhelpful
|
||||
@@ -706,7 +705,7 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
}
|
||||
if ($mod->uservisible) {
|
||||
// show accessibility note only if user can access the module himself
|
||||
$accesstext = get_accesshide(get_string('hiddenfromstudents').': ');
|
||||
$accesstext = get_accesshide(get_string('hiddenfromstudents').':'. $mod->modfullname);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,7 +722,7 @@ class core_course_renderer extends plugin_renderer_base {
|
||||
|
||||
// Display link itself.
|
||||
$activitylink = html_writer::empty_tag('img', array('src' => $mod->get_icon_url(),
|
||||
'class' => 'iconlarge activityicon', 'alt' => $mod->modfullname)) . $accesstext .
|
||||
'class' => 'iconlarge activityicon', 'alt' => ' ', 'role' => 'presentation')) . $accesstext .
|
||||
html_writer::tag('span', $instancename . $altname, array('class' => 'instancename'));
|
||||
if ($mod->uservisible) {
|
||||
$output .= html_writer::link($url, $activitylink, array('class' => $linkclasses, 'onclick' => $onclick)) .
|
||||
|
||||
@@ -27,21 +27,21 @@ Feature: Toggle activities groups mode from the course page
|
||||
| Force group mode | No |
|
||||
When I press "Save changes"
|
||||
Then "No groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And I click on "No groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And I wait "3" seconds
|
||||
And "Separate groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And I reload the page
|
||||
And "Separate groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groups')]" "xpath_element" should exists
|
||||
And I click on "Separate groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And I wait "3" seconds
|
||||
And "Visible groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And I reload the page
|
||||
And "Visible groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupv')]" "xpath_element" should exists
|
||||
And I click on "Visible groups (Click to change)" "link" in the "Test forum name" activity
|
||||
And "No groups (Click to change)" "link" should exists
|
||||
And ".//a//img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
And "//a/child::img[contains(@src, 'groupn')]" "xpath_element" should exists
|
||||
|
||||
@@ -26,7 +26,7 @@ Feature: Indent items on the course page
|
||||
When I indent right "Test glossary name" activity
|
||||
Then "#section-1 li.glossary div.mod-indent-1" "css_element" should exists
|
||||
And I indent right "Test glossary name" activity
|
||||
And "//*[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should exists
|
||||
And "//li[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should exists
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should exists
|
||||
And I reload the page
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should exists
|
||||
@@ -34,4 +34,4 @@ Feature: Indent items on the course page
|
||||
And I indent left "Test glossary name" activity
|
||||
And "#section-1 li.glossary div.mod-indent-2" "css_element" should not exists
|
||||
And "#section-1 li.glossary div.mod-indent-1" "css_element" should not exists
|
||||
And "//*[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should not exists
|
||||
And "//li[@id='section-1']/descendant::li[contains(concat(' ', @class, ' '), ' glossary ')]/descendant::a[@title='Move left']" "xpath_element" should not exists
|
||||
|
||||
@@ -48,7 +48,7 @@ class behat_course extends behat_base {
|
||||
* @Given /^I turn editing mode on$/
|
||||
*/
|
||||
public function i_turn_editing_mode_on() {
|
||||
return new Given('I press "Turn editing on"');
|
||||
return new Given('I press "' . get_string('turneditingon') . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +56,7 @@ class behat_course extends behat_base {
|
||||
* @Given /^I turn editing mode off$/
|
||||
*/
|
||||
public function i_turn_editing_mode_off() {
|
||||
return new Given('I press "Turn editing off"');
|
||||
return new Given('I press "' . get_string('turneditingoff') . '"');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,9 +68,9 @@ class behat_course extends behat_base {
|
||||
public function i_create_a_course_with(TableNode $table) {
|
||||
return array(
|
||||
new Given('I go to the courses management page'),
|
||||
new Given('I press "Add a new course"'),
|
||||
new Given('I press "' . get_string('addnewcourse') . '"'),
|
||||
new Given('I fill the moodle form with:', $table),
|
||||
new Given('I press "Save changes"')
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,9 +83,9 @@ class behat_course extends behat_base {
|
||||
|
||||
return array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I expand "Site administration" node'),
|
||||
new Given('I expand "Courses" node'),
|
||||
new Given('I follow "Add/edit courses"'),
|
||||
new Given('I expand "' . get_string('administrationsite') . '" node'),
|
||||
new Given('I expand "' . get_string('courses', 'admin') . '" node'),
|
||||
new Given('I follow "' . get_string('coursemgmt', 'admin') . '"'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -100,9 +100,9 @@ class behat_course extends behat_base {
|
||||
public function i_add_to_section_and_i_fill_the_form_with($activity, $section, TableNode $data) {
|
||||
|
||||
return array(
|
||||
new Given('I add a "'.$activity.'" to section "'.$section.'"'),
|
||||
new Given('I add a "' . $this->escape($activity) . '" to section "' . $this->escape($section) . '"'),
|
||||
new Given('I fill the moodle form with:', $data),
|
||||
new Given('I press "Save and return to course"')
|
||||
new Given('I press "' . get_string('savechangesandreturntocourse') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,9 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_add_to_section($activity, $section) {
|
||||
|
||||
$sectionxpath = "//*[@id='section-" . $section . "']";
|
||||
$sectionxpath = "//li[@id='section-" . $section . "']";
|
||||
|
||||
$activityliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral(ucfirst($activity));
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
|
||||
@@ -126,9 +128,9 @@ class behat_course extends behat_base {
|
||||
$sectionnode->click();
|
||||
|
||||
// Clicks the selected activity if it exists.
|
||||
$activity = ucfirst($activity);
|
||||
$activityxpath = "//div[@id='chooseform']/descendant::label" .
|
||||
"/descendant::span[contains(concat(' ', @class, ' '), ' typename ')][contains(.,'" . $activity . "')]" .
|
||||
"/descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' typename ')]" .
|
||||
"[contains(., $activityliteral)]" .
|
||||
"/parent::label/child::input";
|
||||
$activitynode = $this->find('xpath', $activityxpath);
|
||||
$activitynode->doubleClick();
|
||||
@@ -137,8 +139,8 @@ class behat_course extends behat_base {
|
||||
// Without Javascript.
|
||||
|
||||
// Selecting the option from the select box which contains the option.
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', @class, ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[contains(., '" . $activity . "')]";
|
||||
$selectxpath = $sectionxpath . "/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' section_add_menus ')]" .
|
||||
"/descendant::select[contains(., $activityliteral)]";
|
||||
$selectnode = $this->find('xpath', $selectxpath);
|
||||
$selectnode->selectOption($activity);
|
||||
|
||||
@@ -162,7 +164,7 @@ class behat_course extends behat_base {
|
||||
$xpath = $this->section_exists($sectionnumber);
|
||||
|
||||
return array(
|
||||
new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $xpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . get_string('markthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@@ -179,7 +181,7 @@ class behat_course extends behat_base {
|
||||
$xpath = $this->section_exists($sectionnumber);
|
||||
|
||||
return array(
|
||||
new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $xpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . get_string('markedthistopic') . '" "link" in the "' . $this->escape($xpath) . '" "xpath_element"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@@ -268,7 +270,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// Section should be hidden.
|
||||
$exception = new ExpectationException('The section is not hidden', $this->getSession());
|
||||
$this->find('xpath', $sectionxpath . "[contains(concat(' ', @class, ' '), ' hidden ')]", $exception);
|
||||
$this->find('xpath', $sectionxpath . "[contains(concat(' ', normalize-space(@class), ' '), ' hidden ')]", $exception);
|
||||
|
||||
// The checking are different depending on user permissions.
|
||||
if ($this->is_course_editor()) {
|
||||
@@ -284,8 +286,8 @@ class behat_course extends behat_base {
|
||||
foreach ($activities as $activity) {
|
||||
|
||||
// Dimmed.
|
||||
$this->find('xpath', "//div[contains(concat(' ', @class, ' '), ' activityinstance ')]" .
|
||||
"/a[contains(concat(' ', @class, ' '), ' dimmed ')]", $dimmedexception, $activity);
|
||||
$this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" .
|
||||
"/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
|
||||
|
||||
// Non-JS browsers can not click on img elements.
|
||||
if ($this->running_javascript()) {
|
||||
@@ -319,7 +321,8 @@ class behat_course extends behat_base {
|
||||
$sectionxpath = $this->section_exists($sectionnumber);
|
||||
|
||||
// Section should not be hidden.
|
||||
if (!$this->getSession()->getPage()->find('xpath', $sectionxpath . "[not(contains(concat(' ', @class, ' '), ' hidden '))]")) {
|
||||
$xpath = $sectionxpath . "[not(contains(concat(' ', normalize-space(@class), ' '), ' hidden '))]";
|
||||
if (!$this->getSession()->getPage()->find('xpath', $xpath)) {
|
||||
throw new ExpectationException('The section is hidden', $this->getSession());
|
||||
}
|
||||
|
||||
@@ -449,10 +452,11 @@ class behat_course extends behat_base {
|
||||
// JS enabled.
|
||||
if ($this->running_javascript()) {
|
||||
|
||||
$destinationxpath = $sectionxpath . "/descendant::ul[contains(@class, 'yui3-dd-drop')]";
|
||||
$destinationxpath = $sectionxpath . "/descendant::ul[contains(concat(' ', normalize-space(@class), ' '), ' yui3-dd-drop ')]";
|
||||
|
||||
return array(
|
||||
new Given('I drag "' . $activitynode->getXpath() . '" "xpath_element" and I drop it in "' . $destinationxpath . '" "xpath_element"'),
|
||||
new Given('I drag "' . $this->escape($activitynode->getXpath()) . '" "xpath_element" ' .
|
||||
'and I drop it in "' . $this->escape($destinationxpath) . '" "xpath_element"'),
|
||||
);
|
||||
|
||||
} else {
|
||||
@@ -460,8 +464,8 @@ class behat_course extends behat_base {
|
||||
|
||||
// Moving to the fist spot of the section (before all other section's activities).
|
||||
return array(
|
||||
new Given('I click on "a.editing_move" "css_element" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "li.movehere a" "css_element" in the "' . $sectionxpath . '" "xpath_element"'),
|
||||
new Given('I click on "a.editing_move" "css_element" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I click on "li.movehere a" "css_element" in the "' . $this->escape($sectionxpath) . '" "xpath_element"'),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -482,8 +486,8 @@ class behat_course extends behat_base {
|
||||
|
||||
// Adding chr(10) to save changes.
|
||||
return array(
|
||||
new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $activityname .'" activity'),
|
||||
new Given('I fill in "title" with "' . $newactivityname . chr(10) . '"'),
|
||||
new Given('I click on "' . get_string('edittitle') . '" "link" in the "' . $this->escape($activityname) .'" activity'),
|
||||
new Given('I fill in "title" with "' . $this->escape($newactivityname) . chr(10) . '"'),
|
||||
new Given('I wait "2" seconds')
|
||||
);
|
||||
}
|
||||
@@ -497,7 +501,7 @@ class behat_course extends behat_base {
|
||||
public function i_indent_right_activity($activityname) {
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $activityname . '" activity')
|
||||
new Given('I click on "' . get_string('moveright') . '" "link" in the "' . $this->escape($activityname) . '" activity')
|
||||
);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
@@ -516,7 +520,7 @@ class behat_course extends behat_base {
|
||||
public function i_indent_left_activity($activityname) {
|
||||
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $activityname . '" activity')
|
||||
new Given('I click on "' . get_string('moveleft') . '" "link" in the "' . $this->escape($activityname) . '" activity')
|
||||
);
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
@@ -553,7 +557,7 @@ class behat_course extends behat_base {
|
||||
|
||||
// With JS disabled.
|
||||
$steps = array(
|
||||
new Given('I click on "' . $deletestring . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . $this->escape($deletestring) . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('yes') . '"')
|
||||
);
|
||||
|
||||
@@ -569,7 +573,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_duplicate_activity($activityname) {
|
||||
return array(
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('continue') .'"'),
|
||||
new Given('I press "' . get_string('duplicatecontcourse') .'"')
|
||||
);
|
||||
@@ -584,7 +588,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
public function i_duplicate_activity_editing_the_new_copy_with($activityname, TableNode $data) {
|
||||
return array(
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $activityname . '" activity'),
|
||||
new Given('I click on "' . get_string('duplicate') . '" "link" in the "' . $this->escape($activityname) . '" activity'),
|
||||
new Given('I press "' . get_string('continue') .'"'),
|
||||
new Given('I press "' . get_string('duplicatecontedit') . '"'),
|
||||
new Given('I fill the moodle form with:', $data),
|
||||
@@ -657,9 +661,9 @@ class behat_course extends behat_base {
|
||||
$courseformat = $this->get_course_format();
|
||||
|
||||
// Checking the show button alt text and show icon.
|
||||
$showtext = get_string('showfromothers', $courseformat);
|
||||
$linkxpath = $xpath . "/descendant::a[@title='". $showtext ."']";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt='". $showtext ."'][contains(@src, 'show')]";
|
||||
$showtext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('showfromothers', $courseformat));
|
||||
$linkxpath = $xpath . "/descendant::a[@title=$showtext]";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt=$showtext][contains(@src, 'show')]";
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Show section icon ');
|
||||
$this->find('xpath', $imgxpath, $exception);
|
||||
@@ -684,9 +688,9 @@ class behat_course extends behat_base {
|
||||
$courseformat = $this->get_course_format();
|
||||
|
||||
// Checking the hide button alt text and hide icon.
|
||||
$hidetext = get_string('hidefromothers', $courseformat);
|
||||
$linkxpath = $xpath . "/descendant::a[@title='" . $hidetext . "']";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt='" . $hidetext ."'][contains(@src, 'hide')]";
|
||||
$hidetext = $this->getSession()->getSelectorsHandler()->xpathLiteral(get_string('hidefromothers', $courseformat));
|
||||
$linkxpath = $xpath . "/descendant::a[@title=$hidetext]";
|
||||
$imgxpath = $linkxpath . "/descendant::img[@alt=$hidetext][contains(@src, 'hide')]";
|
||||
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Hide section icon ');
|
||||
$this->find('xpath', $imgxpath, $exception);
|
||||
@@ -730,7 +734,7 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
protected function get_section_activities($sectionxpath) {
|
||||
|
||||
$xpath = $sectionxpath . "/descendant::li[contains(concat(' ', @class, ' '), ' activity ')]";
|
||||
$xpath = $sectionxpath . "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')]";
|
||||
|
||||
// We spin here, as activities usually require a lot of time to load.
|
||||
try {
|
||||
@@ -751,8 +755,8 @@ class behat_course extends behat_base {
|
||||
*/
|
||||
protected function get_activity_node($activityname) {
|
||||
|
||||
$activityname = str_replace("'", "\'", $activityname);
|
||||
$xpath = "//li[contains(concat(' ', @class, ' '), ' activity ')][contains(., '" .$activityname. "')]";
|
||||
$activityname = $this->getSession()->getSelectorsHandler()->xpathLiteral($activityname);
|
||||
$xpath = "//li[contains(concat(' ', normalize-space(@class), ' '), ' activity ')][contains(., $activityname)]";
|
||||
|
||||
return $this->find('xpath', $xpath);
|
||||
}
|
||||
@@ -765,8 +769,8 @@ class behat_course extends behat_base {
|
||||
protected function is_course_editor() {
|
||||
|
||||
// We don't need to behat_base::spin() here as all is already loaded.
|
||||
if (!$this->getSession()->getPage()->findButton('Turn editing off') &&
|
||||
!$this->getSession()->getPage()->findButton('Turn editing on')) {
|
||||
if (!$this->getSession()->getPage()->findButton(get_string('turneditingoff')) &&
|
||||
!$this->getSession()->getPage()->findButton(get_string('turneditingon'))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ Feature: Force group mode in a course
|
||||
| Group mode | Separate groups |
|
||||
| Force group mode | Yes |
|
||||
When I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Separate groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
@javascript
|
||||
Scenario: Forced group mode using visible groups
|
||||
@@ -40,11 +40,11 @@ Feature: Force group mode in a course
|
||||
| Group mode | Visible groups |
|
||||
| Force group mode | Yes |
|
||||
And I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'Visible groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
@javascript
|
||||
Scenario: Forced group mode without groups
|
||||
@@ -52,9 +52,9 @@ Feature: Force group mode in a course
|
||||
| Group mode | No groups |
|
||||
| Force group mode | Yes |
|
||||
And I press "Save changes"
|
||||
Then ".//a//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And ".//a//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And ".//img[contains(./@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
Then "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
And I click on "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" in the "li.activity.chat" "css_element"
|
||||
And "//a/child::img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should not exists
|
||||
And "//img[contains(@alt, 'No groups (forced mode)')]" "xpath_element" should exists
|
||||
|
||||
|
||||
@@ -50,11 +50,11 @@ class behat_enrol extends behat_base {
|
||||
public function i_add_enrolment_method_with($enrolmethod, TableNode $table) {
|
||||
|
||||
return array(
|
||||
new Given('I expand "Users" node'),
|
||||
new Given('I follow "Enrolment methods"'),
|
||||
new Given('I select "' . $enrolmethod . '" from "Add method"'),
|
||||
new Given('I expand "' . get_string('users', 'admin') . '" node'),
|
||||
new Given('I follow "' . get_string('type_enrol_plural', 'plugin') . '"'),
|
||||
new Given('I select "' . $this->escape($enrolmethod) . '" from "' . get_string('addinstance', 'enrol') . '"'),
|
||||
new Given('I fill the moodle form with:', $table),
|
||||
new Given('I press "Add method"')
|
||||
new Given('I press "' . get_string('addinstance', 'enrol') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -820,10 +820,9 @@ class gradingform_guide_instance extends gradingform_instance {
|
||||
/**
|
||||
* Calculates the grade to be pushed to the gradebook
|
||||
*
|
||||
* @return int the valid grade from $this->get_controller()->get_grade_range()
|
||||
* @return float|int the valid grade from $this->get_controller()->get_grade_range()
|
||||
*/
|
||||
public function get_grade() {
|
||||
global $DB, $USER;
|
||||
$grade = $this->get_guide_filling();
|
||||
|
||||
if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
|
||||
@@ -842,8 +841,12 @@ class gradingform_guide_instance extends gradingform_instance {
|
||||
foreach ($grade['criteria'] as $record) {
|
||||
$curscore += $record['score'];
|
||||
}
|
||||
return round(($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*
|
||||
($maxgrade-$mingrade), 0) + $mingrade;
|
||||
$gradeoffset = ($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*
|
||||
($maxgrade-$mingrade);
|
||||
if ($this->get_controller()->get_allow_grade_decimals()) {
|
||||
return $gradeoffset + $mingrade;
|
||||
}
|
||||
return round($gradeoffset, 0) + $mingrade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'gradingform_guide';
|
||||
$plugin->version = 2013050100;
|
||||
$plugin->requires = 2013050100;
|
||||
$plugin->version = 2013051401.05;
|
||||
$plugin->requires = 2013051401.05;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
@@ -73,6 +73,9 @@ abstract class gradingform_controller {
|
||||
/** @var array graderange array of valid grades for this area. Use set_grade_range and get_grade_range to access this */
|
||||
private $graderange = null;
|
||||
|
||||
/** @var bool if decimal values are allowed as grades. */
|
||||
private $allowgradedecimals = false;
|
||||
|
||||
/** @var boolean|null cached result of function has_active_instances() */
|
||||
protected $hasactiveinstances = null;
|
||||
|
||||
@@ -622,13 +625,23 @@ abstract class gradingform_controller {
|
||||
|
||||
/**
|
||||
* Sets the range of grades used in this area. This is usually either range like 0-100
|
||||
* or the scale where keys start from 1. Typical use:
|
||||
* $controller->set_grade_range(make_grades_menu($gradingtype));
|
||||
* or the scale where keys start from 1.
|
||||
*
|
||||
* @param array $graderange
|
||||
* Typically modules will call it:
|
||||
* $controller->set_grade_range(make_grades_menu($gradingtype), $gradingtype > 0);
|
||||
* Negative $gradingtype means that scale is used and the grade must be rounded
|
||||
* to the nearest int. Positive $gradingtype means that range 0..$gradingtype
|
||||
* is used for the grades and in this case grade does not have to be rounded.
|
||||
*
|
||||
* Sometimes modules always expect grade to be rounded (like mod_assignment does).
|
||||
*
|
||||
* @param array $graderange array where first _key_ is the minimum grade and the
|
||||
* last key is the maximum grade.
|
||||
* @param bool $allowgradedecimals if decimal values are allowed as grades.
|
||||
*/
|
||||
public final function set_grade_range(array $graderange) {
|
||||
public final function set_grade_range(array $graderange, $allowgradedecimals = false) {
|
||||
$this->graderange = $graderange;
|
||||
$this->allowgradedecimals = $allowgradedecimals;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,6 +656,15 @@ abstract class gradingform_controller {
|
||||
return $this->graderange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if decimal values are allowed as grades
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public final function get_allow_grade_decimals() {
|
||||
return $this->allowgradedecimals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by sub classes that wish to make definition details available to web services.
|
||||
* When not overridden, only definition data common to all grading methods is made available.
|
||||
@@ -866,7 +888,11 @@ abstract class gradingform_instance {
|
||||
/**
|
||||
* Calculates the grade to be pushed to the gradebook
|
||||
*
|
||||
* @return int the valid grade from $this->get_controller()->get_grade_range()
|
||||
* Returned grade must be in range $this->get_controller()->get_grade_range()
|
||||
* Plugins must returned grade converted to int unless
|
||||
* $this->get_controller()->get_allow_grade_decimals() is true.
|
||||
*
|
||||
* @return float|int
|
||||
*/
|
||||
abstract public function get_grade();
|
||||
|
||||
|
||||
@@ -814,10 +814,9 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
/**
|
||||
* Calculates the grade to be pushed to the gradebook
|
||||
*
|
||||
* @return int the valid grade from $this->get_controller()->get_grade_range()
|
||||
* @return float|int the valid grade from $this->get_controller()->get_grade_range()
|
||||
*/
|
||||
public function get_grade() {
|
||||
global $DB, $USER;
|
||||
$grade = $this->get_rubric_filling();
|
||||
|
||||
if (!($scores = $this->get_controller()->get_min_max_score()) || $scores['maxscore'] <= $scores['minscore']) {
|
||||
@@ -836,7 +835,11 @@ class gradingform_rubric_instance extends gradingform_instance {
|
||||
foreach ($grade['criteria'] as $id => $record) {
|
||||
$curscore += $this->get_controller()->get_definition()->rubric_criteria[$id]['levels'][$record['levelid']]['score'];
|
||||
}
|
||||
return round(($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*($maxgrade-$mingrade), 0) + $mingrade;
|
||||
$gradeoffset = ($curscore-$scores['minscore'])/($scores['maxscore']-$scores['minscore'])*($maxgrade-$mingrade);
|
||||
if ($this->get_controller()->get_allow_grade_decimals()) {
|
||||
return $gradeoffset + $mingrade;
|
||||
}
|
||||
return round($gradeoffset, 0) + $mingrade;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
|
||||
.gradingform_rubric .plainvalue.empty {font-style: italic; color: #AAA;}
|
||||
|
||||
.gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0;bottom:0;}
|
||||
.gradingform_rubric.editor .criterion .levels .level .delete {position:absolute;right:0;}
|
||||
.gradingform_rubric .criterion .levels .level .score {font-style:italic;color:#575;font-weight: bold;margin-top:5px;white-space:nowrap;}
|
||||
.gradingform_rubric .criterion .levels .level .score .scorevalue {padding-right:5px;}
|
||||
|
||||
@@ -106,7 +106,7 @@
|
||||
.gradingform_rubric.editor .addcriterion input,
|
||||
.gradingform_rubric.editor .addlevel input {background: transparent url([[pix:t/add]]) no-repeat top left ;display:block;color:#555555;font-weight:bold;text-decoration:none;}
|
||||
.gradingform_rubric.editor .addcriterion input {background-position: 5px 8px;height:30px;line-height:29px;margin-bottom:14px;padding-left:20px;padding-right:10px;}
|
||||
.gradingform_rubric.editor .addlevel input {background-position: 5px 5px;height:25px;line-height:24px;margin-bottom:10px;padding-left:18px;padding-right:8px;}
|
||||
.gradingform_rubric.editor .addlevel input {background-position: 5px 5px;height:25px;line-height:24px;margin-bottom:45px;padding-left:18px;padding-right:8px;}
|
||||
|
||||
.gradingform_rubric .options .optionsheading {font-weight:bold;font-size:1.1em;padding-bottom:5px;}
|
||||
.gradingform_rubric .options .option {padding-bottom:2px;}
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'gradingform_rubric';
|
||||
$plugin->version = 2013050100;
|
||||
$plugin->version = 2013051401.05;
|
||||
|
||||
$plugin->requires = 2013050100;
|
||||
$plugin->requires = 2013051401.05;
|
||||
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
This files describes API changes in /grade/grading/form/* - Advanced grading methods
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 2.5.2 ===
|
||||
|
||||
* Grading methods now can return grade with decimals. See API functions
|
||||
gradingform_controller::set_grade_range() and
|
||||
gradingform_controller::get_allow_grade_decimals(), and also examples
|
||||
in gradingform_rubric_instance::get_grade().
|
||||
@@ -226,6 +226,10 @@ class grade_report_grader extends grade_report {
|
||||
$changedgrades = true;
|
||||
|
||||
} else if ($datatype === 'feedback') {
|
||||
// If quick grading is on, feedback needs to be compared without line breaks.
|
||||
if ($this->get_pref('quickgrading')) {
|
||||
$oldvalue->feedback = preg_replace("/\r\n|\r|\n/", "", $oldvalue->feedback);
|
||||
}
|
||||
if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -51,36 +51,39 @@ class behat_groups extends behat_base {
|
||||
global $DB;
|
||||
|
||||
$user = $DB->get_record('user', array('username' => $username));
|
||||
$userfullname = fullname($user);
|
||||
$userfullname = $this->getSession()->getSelectorsHandler()->xpathLiteral(fullname($user));
|
||||
|
||||
// Using a xpath liternal to avoid problems with quotes and double quotes.
|
||||
$groupname = $this->getSession()->getSelectorsHandler()->xpathLiteral($groupname);
|
||||
|
||||
// We don't know the option text as it contains the number of users in the group.
|
||||
$select = $this->find_field('groups');
|
||||
$xpath = "//select[@id='groups']/descendant::option[contains(., '" . $groupname . "')]";
|
||||
$xpath = "//select[@id='groups']/descendant::option[contains(., $groupname)]";
|
||||
$groupoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $groupoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
|
||||
// Here we don't need to wait for the AJAX response.
|
||||
$this->find_button('Add/remove users')->click();
|
||||
$this->find_button(get_string('adduserstogroup', 'group'))->click();
|
||||
|
||||
// Wait for add/remove members page to be loaded.
|
||||
$this->getSession()->wait(self::TIMEOUT, '(document.readyState === "complete")');
|
||||
|
||||
// Getting the option and selecting it.
|
||||
$select = $this->find_field('addselect');
|
||||
$xpath = "//select[@id='addselect']/descendant::option[contains(., '" . $userfullname . "')]";
|
||||
$xpath = "//select[@id='addselect']/descendant::option[contains(., $userfullname)]";
|
||||
$memberoption = $this->find('xpath', $xpath);
|
||||
$fulloption = $memberoption->getText();
|
||||
$select->selectOption($fulloption);
|
||||
|
||||
// Click add button.
|
||||
$this->find_button('Add')->click();
|
||||
$this->find_button(get_string('add'))->click();
|
||||
|
||||
// Wait for the page to load.
|
||||
$this->getSession()->wait(self::TIMEOUT, '(document.readyState === "complete")');
|
||||
|
||||
// Returning to the main groups page.
|
||||
$this->find_button('Back to groups')->click();
|
||||
$this->find_button(get_string('backtogroups', 'group'))->click();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -198,6 +198,7 @@ $string['donotaward'] = 'Currently, this badge is not active, so it cannot be aw
|
||||
$string['editsettings'] = 'Edit settings';
|
||||
$string['enablebadges'] = 'Enable badges';
|
||||
$string['error:backpacknotavailable'] = 'Your site is not accessible from the Internet, so any badges issued from this site cannot be verified by external backpack services.';
|
||||
$string['error:backpackproblem'] = 'There was a problem connecting to your backpack service provider. Please try again later.';
|
||||
$string['error:cannotact'] = 'Cannot activate the badge. ';
|
||||
$string['error:cannotawardbadge'] = 'Cannot award badge to a user.';
|
||||
$string['error:clone'] = 'Cannot clone the badge.';
|
||||
|
||||
@@ -1348,3 +1348,19 @@ function badges_handle_course_deletion($courseid) {
|
||||
$DB->update_record('badge', $toupdate);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads JS files required for backpack support.
|
||||
*
|
||||
* @uses $CFG, $PAGE
|
||||
* @return void
|
||||
*/
|
||||
function badges_setup_backpack_js() {
|
||||
global $CFG, $PAGE;
|
||||
if (!empty($CFG->badges_allowexternalbackpack)) {
|
||||
$PAGE->requires->string_for_js('error:backpackproblem', 'badges');
|
||||
$protocol = (strpos($CFG->wwwroot, 'https://') === 0) ? 'https://' : 'http://';
|
||||
$PAGE->requires->js(new moodle_url($protocol . 'backpack.openbadges.org/issuer.js'), true);
|
||||
$PAGE->requires->js('/badges/backpack.js', true);
|
||||
}
|
||||
}
|
||||
|
||||
+25
-17
@@ -64,10 +64,12 @@ class behat_files extends behat_base {
|
||||
$exception = new ExpectationException('"' . $filepickerelement . '" filepicker can not be found', $this->getSession());
|
||||
|
||||
// Gets the ffilemanager node specified by the locator which contains the filepicker container.
|
||||
$filepickerelement = $this->getSession()->getSelectorsHandler()->xpathLiteral($filepickerelement);
|
||||
$filepickercontainer = $this->find(
|
||||
'xpath',
|
||||
"//input[./@id = //label[contains(normalize-space(string(.)), '" . $filepickerelement . "')]/@for]
|
||||
//ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ') or contains(concat(' ', normalize-space(@class), ' '), ' ffilepicker ')]",
|
||||
"//input[./@id = //label[normalize-space(.)=$filepickerelement]/@for]" .
|
||||
"//ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ') or " .
|
||||
"contains(concat(' ', normalize-space(@class), ' '), ' ffilepicker ')]",
|
||||
$exception
|
||||
);
|
||||
|
||||
@@ -117,17 +119,20 @@ class behat_files extends behat_base {
|
||||
|
||||
$exception = new ExpectationException($exceptionmsg, $this->getSession());
|
||||
|
||||
// Avoid quote-related problems.
|
||||
$name = $this->getSession()->getSelectorsHandler()->xpathLiteral($name);
|
||||
|
||||
// Get a filepicker element (folder or file).
|
||||
try {
|
||||
|
||||
// First we look at the folder as we need to click on the contextual menu otherwise it would be opened.
|
||||
$node = $this->find(
|
||||
'xpath',
|
||||
"//div[@class='fp-content']
|
||||
//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')]
|
||||
[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')][contains(normalize-space(string(.)), '" . $name . "')]
|
||||
//descendant::a[contains(concat(' ', normalize-space(@class), ' '), ' fp-contextmenu ')]
|
||||
",
|
||||
"//div[@class='fp-content']" .
|
||||
"//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')]" .
|
||||
"[normalize-space(.)=$name]" .
|
||||
"//descendant::a[contains(concat(' ', normalize-space(@class), ' '), ' fp-contextmenu ')]",
|
||||
$exception,
|
||||
$containernode
|
||||
);
|
||||
@@ -137,10 +142,10 @@ class behat_files extends behat_base {
|
||||
// Here the contextual menu is hidden, we click on the thumbnail.
|
||||
$node = $this->find(
|
||||
'xpath',
|
||||
"//div[@class='fp-content']
|
||||
//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')][contains(normalize-space(string(.)), '" . $name . "')]
|
||||
//descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-thumbnail ')]
|
||||
",
|
||||
"//div[@class='fp-content']" .
|
||||
"//descendant::*[self::div | self::a][contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')]" .
|
||||
"[normalize-space(.)=$name]" .
|
||||
"//descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-thumbnail ')]",
|
||||
false,
|
||||
$containernode
|
||||
);
|
||||
@@ -176,12 +181,15 @@ class behat_files extends behat_base {
|
||||
// Getting the repository link and opening it.
|
||||
$repoexception = new ExpectationException('The "' . $repositoryname . '" repository has not been found', $this->getSession());
|
||||
|
||||
// Avoid problems with both double and single quotes in the same string.
|
||||
$repositoryname = $this->getSession()->getSelectorsHandler()->xpathLiteral($repositoryname);
|
||||
|
||||
// Here we don't need to look inside the selected filepicker because there can only be one modal window.
|
||||
$repositorylink = $this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-area ')]
|
||||
//descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-name ')]
|
||||
[contains(normalize-space(string(.)), '" . $repositoryname . "')]",
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-area ')]" .
|
||||
"//descendant::span[contains(concat(' ', normalize-space(@class), ' '), ' fp-repo-name ')]" .
|
||||
"[normalize-space(.)=$repositoryname]",
|
||||
$repoexception
|
||||
);
|
||||
|
||||
@@ -226,10 +234,10 @@ class behat_files extends behat_base {
|
||||
// only used when accessing the filepicker, there is no filemanager-loading after selecting the file.
|
||||
$this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', @class, ' '), ' filemanager ')]" .
|
||||
"[not(contains(concat(' ', @class, ' '), ' fm-updating '))]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' filemanager ')]" .
|
||||
"[not(contains(concat(' ', normalize-space(@class), ' '), ' fm-updating '))]" .
|
||||
"|" .
|
||||
"//div[contains(concat(' ', @class, ' '), ' filemanager-loading ')]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' filemanager-loading ')]" .
|
||||
"[contains(@style, 'display: none;')]",
|
||||
$exception,
|
||||
$filepickernode
|
||||
|
||||
@@ -58,10 +58,13 @@ class behat_form_select extends behat_form_field {
|
||||
|
||||
// Single select needs an extra click in the option.
|
||||
if (!$this->field->hasAttribute('multiple')) {
|
||||
|
||||
$value = $this->session->getSelectorsHandler()->xpathLiteral($value);
|
||||
|
||||
// Using the driver direcly because Element methods are messy when dealing
|
||||
// with elements inside containers.
|
||||
$optionxpath = $this->field->getXpath() .
|
||||
"/descendant::option[(./@value = '" . $value . "' or contains(normalize-space(string(.)), '" . $value . "'))]";
|
||||
"/descendant::option[(./@value=$value or normalize-space(.)=$value)]";
|
||||
$optionnodes = $this->session->getDriver()->find($optionxpath);
|
||||
if ($optionnodes) {
|
||||
current($optionnodes)->click();
|
||||
|
||||
@@ -141,3 +141,29 @@ function behat_error_handler($errno, $errstr, $errfile, $errline, $errcontext) {
|
||||
// Also use the internal error handler so we keep the usual behaviour.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restrict the config.php settings allowed.
|
||||
*
|
||||
* When running the behat features the config.php
|
||||
* settings should not affect the results.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function behat_clean_init_config() {
|
||||
global $CFG;
|
||||
|
||||
$allowed = array_flip(array(
|
||||
'wwwroot', 'dataroot', 'dirroot', 'admin', 'directorypermissions', 'filepermissions',
|
||||
'dbtype', 'dblibrary', 'dbhost', 'dbname', 'dbuser', 'dbpass', 'prefix', 'dboptions',
|
||||
'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword', 'proxybypass'
|
||||
));
|
||||
|
||||
// Also allowing behat_ prefixed attributes.
|
||||
foreach ($CFG as $key => $value) {
|
||||
if (!isset($allowed[$key]) && strpos($key, 'behat_') !== 0) {
|
||||
unset($CFG->{$key});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,25 +28,18 @@ require('../../../../../config.php');
|
||||
|
||||
// General settings
|
||||
$engine = get_config('tinymce_spellchecker', 'spellengine');
|
||||
if (!$engine) {
|
||||
$engine = 'GoogleSpell';
|
||||
if (!$engine or $engine === 'GoogleSpell') {
|
||||
$engine = 'PSpell';
|
||||
}
|
||||
$config['general.engine'] = $engine;
|
||||
|
||||
// GoogleSpell settings
|
||||
$config['GoogleSpell.proxyhost'] = isset($CFG->proxyhost) ? $CFG->proxyhost : '';
|
||||
$config['GoogleSpell.proxyport'] = isset($CFG->proxyport) ? $CFG->proxyport : '';
|
||||
$config['GoogleSpell.proxytype'] = isset($CFG->proxytype) ? $CFG->proxytype : 'HTML';
|
||||
$config['GoogleSpell.proxyuser'] = isset($CFG->proxyuser) ? $CFG->proxyuser : '';
|
||||
$config['GoogleSpell.proxypassword'] = isset($CFG->proxypassword) ? $CFG->proxypassword : '';
|
||||
|
||||
if ($config['general.engine'] === 'PSpell' || $config['general.engine'] === 'PSpellShell') {
|
||||
if ($config['general.engine'] === 'PSpell') {
|
||||
// PSpell settings
|
||||
$config['PSpell.mode'] = PSPELL_FAST;
|
||||
$config['PSpell.spelling'] = "";
|
||||
$config['PSpell.jargon'] = "";
|
||||
$config['PSpell.encoding'] = "";
|
||||
|
||||
} else if ($config['general.engine'] === 'PSpellShell') {
|
||||
// PSpellShell settings
|
||||
$config['PSpellShell.mode'] = PSPELL_FAST;
|
||||
$config['PSpellShell.aspell'] = $CFG->aspellpath;
|
||||
|
||||
@@ -36,6 +36,12 @@ class tinymce_spellchecker extends editor_tinymce_plugin {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check some speller is configured.
|
||||
$engine = $this->get_config('spellengine', '');
|
||||
if (!$engine or $engine === 'GoogleSpell') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check at least one language is supported.
|
||||
$spelllanguagelist = $this->get_config('spelllanguagelist', '');
|
||||
if ($spelllanguagelist !== '') {
|
||||
|
||||
@@ -26,11 +26,11 @@ defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($ADMIN->fulltree) {
|
||||
$options = array(
|
||||
''=>get_string('none'),
|
||||
'PSpell'=>'PSpell',
|
||||
'GoogleSpell'=>'Google Spell',
|
||||
'PSpellShell'=>'PSpellShell');
|
||||
$settings->add(new admin_setting_configselect('tinymce_spellchecker/spellengine',
|
||||
get_string('spellengine', 'admin'), '', 'GoogleSpell', $options));
|
||||
get_string('spellengine', 'admin'), '', '', $options));
|
||||
$settings->add(new admin_setting_configtextarea('tinymce_spellchecker/spelllanguagelist',
|
||||
get_string('spelllanguagelist', 'admin'), '',
|
||||
'+English=en,Danish=da,Dutch=nl,Finnish=fi,French=fr,German=de,Italian=it,Polish=pl,' .
|
||||
|
||||
@@ -1266,7 +1266,8 @@ class global_navigation extends navigation_node {
|
||||
// Remove any empty root nodes
|
||||
foreach ($this->rootnodes as $node) {
|
||||
// Dont remove the home node
|
||||
if ($node->key !== 'home' && !$node->has_children()) {
|
||||
/** @var navigation_node $node */
|
||||
if ($node->key !== 'home' && !$node->has_children() && !$node->isactive) {
|
||||
$node->remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,10 @@ if (!defined('BEHAT_SITE_RUNNING') && !empty($CFG->behat_dataroot) &&
|
||||
// actions like reset the site or use data generators.
|
||||
define('BEHAT_SITE_RUNNING', true);
|
||||
|
||||
// Clean extra config.php settings.
|
||||
require_once(__DIR__ . '/../lib/behat/lib.php');
|
||||
behat_clean_init_config();
|
||||
|
||||
$CFG->wwwroot = $CFG->behat_wwwroot;
|
||||
$CFG->passwordsaltmain = 'moodle';
|
||||
$CFG->prefix = $CFG->behat_prefix;
|
||||
|
||||
@@ -1686,6 +1686,7 @@ class table_xhtml_export_format extends table_default_export_format_parent {
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xml:lang="en" lang="en">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
<style type="text/css">/*<![CDATA[*/
|
||||
|
||||
.flexible th {
|
||||
|
||||
@@ -110,34 +110,31 @@ class behat_forms extends behat_base {
|
||||
// behat_base::find() throws an exception if there are no elements, we should not fail a test because of this.
|
||||
try {
|
||||
|
||||
// Expand fieldsets.
|
||||
$fieldsets = $this->find_all('css', 'fieldset.collapsed a.fheader');
|
||||
|
||||
// We are supposed to have fieldsets here, otherwise exception.
|
||||
|
||||
// Funny thing about this, with find_all() we specify a pattern and each element matching the pattern is added to the array
|
||||
// with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
|
||||
// anymore (is not collapsed) so [1] becomes [0], that's why we always click on the first XPath match, will be always the next one.
|
||||
$iterations = count($fieldsets);
|
||||
for ($i = 0; $i < $iterations; $i++) {
|
||||
$fieldsets[0]->click();
|
||||
}
|
||||
// Expand fieldsets link.
|
||||
$collapseexpandlink = $this->find('xpath', "//div[@class='collapsible-actions']" .
|
||||
"/descendant::a[contains(concat(' ', @class, ' '), ' collapseexpand ')]" .
|
||||
"[not(contains(concat(' ', @class, ' '), ' collapse-all '))]"
|
||||
);
|
||||
$collapseexpandlink->click();
|
||||
|
||||
} catch (ElementNotFoundException $e) {
|
||||
// We continue if there are not expanded fields.
|
||||
// We continue if there are not expandable fields.
|
||||
}
|
||||
|
||||
// Different try & catch as we can have expanded fieldsets with advanced fields on them.
|
||||
try {
|
||||
|
||||
// Show all fields.
|
||||
$showmorestr = get_string('showmore', 'form');
|
||||
$showmores = $this->find_all('xpath', "//a[contains(concat(' ', normalize-space(.), ' '), '" . $showmorestr . "')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]");
|
||||
// Expand all fields xpath.
|
||||
$showmorexpath = "//a[normalize-space(.)='" . get_string('showmore', 'form') . "']" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' moreless-toggler')]";
|
||||
|
||||
// We are supposed to have 'show more's here, otherwise exception.
|
||||
// We don't wait here as we already waited when getting the expand fieldsets links.
|
||||
$showmores = $this->getSession()->getPage()->findAll('xpath', $showmorexpath);
|
||||
|
||||
// Same funny case, after clicking on the element the [1] showmore link becomes the [0].
|
||||
// Funny thing about this, with findAll() we specify a pattern and each element matching the pattern is added to the array
|
||||
// with of xpaths with a [0], [1]... sufix, but when we click on an element it does not matches the specified xpath
|
||||
// anymore (now is a "Show less..." link) so [1] becomes [0], that's why we always click on the first XPath match,
|
||||
// will be always the next one.
|
||||
$iterations = count($showmores);
|
||||
for ($i = 0; $i < $iterations; $i++) {
|
||||
$showmores[0]->click();
|
||||
@@ -186,9 +183,12 @@ class behat_forms extends behat_base {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single select needs an extra click in the option.
|
||||
if (!$selectnode->hasAttribute('multiple')) {
|
||||
// Single select needs an extra click in the option.
|
||||
$xpath = ".//option[(./@value = '" . $option . "' or contains(normalize-space(string(.)), '" . $option . "'))]";
|
||||
|
||||
// Avoid quotes problems.
|
||||
$option = $this->getSession()->getSelectorsHandler()->xpathLiteral($option);
|
||||
$xpath = "//option[(./@value=$option or normalize-space(.)=$option)]";
|
||||
$optionnode = $this->find('xpath', $xpath, false, $selectnode);
|
||||
$optionnode->click();
|
||||
} else {
|
||||
|
||||
@@ -242,8 +242,8 @@ class behat_general extends behat_base {
|
||||
|
||||
// The table row container.
|
||||
$nocontainerexception = new ElementNotFoundException($this->getSession(), '"' . $tablerowtext . '" row text ');
|
||||
$tablerowtext = str_replace("'", "\'", $tablerowtext);
|
||||
$rownode = $this->find('xpath', "//tr[contains(., '" . $tablerowtext . "')]", $nocontainerexception);
|
||||
$tablerowtext = $this->getSession()->getSelectorsHandler()->xpathLiteral($tablerowtext);
|
||||
$rownode = $this->find('xpath', "//tr[contains(., $tablerowtext)]", $nocontainerexception);
|
||||
|
||||
// Looking for the element DOM node inside the specified row.
|
||||
list($selector, $locator) = $this->transform_selector($selectortype, $element);
|
||||
@@ -285,7 +285,7 @@ class behat_general extends behat_base {
|
||||
public function assert_page_contains_text($text) {
|
||||
|
||||
$xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text);
|
||||
$xpath = "/descendant::*[contains(., " . $xpathliteral. ")]";
|
||||
$xpath = "/descendant::*[contains(., $xpathliteral)]";
|
||||
|
||||
// Wait until it finds the text, otherwise custom exception.
|
||||
try {
|
||||
@@ -305,7 +305,7 @@ class behat_general extends behat_base {
|
||||
public function assert_page_not_contains_text($text) {
|
||||
|
||||
$xpathliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text);
|
||||
$xpath = "/descendant::*[not(contains(., " . $xpathliteral. "))]";
|
||||
$xpath = "/descendant::*[not(contains(., $xpathliteral))]";
|
||||
|
||||
// Wait until it finds the text, otherwise custom exception.
|
||||
try {
|
||||
|
||||
@@ -244,7 +244,26 @@ class behat_hooks extends behat_base {
|
||||
try {
|
||||
|
||||
// Exceptions.
|
||||
if ($errormsg = $this->getSession()->getPage()->find('css', '.errorbox p.errormessage')) {
|
||||
$exceptionsxpath = "//*[contains(concat(' ', normalize-space(@class), ' '), ' errorbox ')]" .
|
||||
"/descendant::p[contains(concat(' ', normalize-space(@class), ' '), ' errormessage ')]";
|
||||
// Debugging messages.
|
||||
$debuggingxpath = "//*[contains(concat(' ', normalize-space(@class), ' '), ' debuggingmessage ')]";
|
||||
// PHP debug messages.
|
||||
$phperrorxpath = "//*[contains(concat(' ', normalize-space(@class), ' '), ' phpdebugmessage ')]";
|
||||
// Any other backtrace.
|
||||
$othersxpath = "(//*[contains(., ': call to ')])[1]";
|
||||
|
||||
$xpaths = array($exceptionsxpath, $debuggingxpath, $phperrorxpath, $othersxpath);
|
||||
$joinedxpath = implode(' | ', $xpaths);
|
||||
|
||||
// Joined xpath expression. Most of the time there will be no exceptions, so this pre-check
|
||||
// is faster than to send the 4 xpath queries for each step.
|
||||
if (!$this->getSession()->getDriver()->find($joinedxpath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exceptions.
|
||||
if ($errormsg = $this->getSession()->getPage()->find('xpath', $exceptionsxpath)) {
|
||||
|
||||
// Getting the debugging info and the backtrace.
|
||||
$errorinfoboxes = $this->getSession()->getPage()->findAll('css', 'div.notifytiny');
|
||||
@@ -256,7 +275,7 @@ class behat_hooks extends behat_base {
|
||||
}
|
||||
|
||||
// Debugging messages.
|
||||
if ($debuggingmessages = $this->getSession()->getPage()->findAll('css', '.debuggingmessage')) {
|
||||
if ($debuggingmessages = $this->getSession()->getPage()->findAll('xpath', $debuggingxpath)) {
|
||||
$msgs = array();
|
||||
foreach ($debuggingmessages as $debuggingmessage) {
|
||||
$msgs[] = $this->get_debug_text($debuggingmessage->getHtml());
|
||||
@@ -266,7 +285,7 @@ class behat_hooks extends behat_base {
|
||||
}
|
||||
|
||||
// PHP debug messages.
|
||||
if ($phpmessages = $this->getSession()->getPage()->findAll('css', '.phpdebugmessage')) {
|
||||
if ($phpmessages = $this->getSession()->getPage()->findAll('xpath', $phperrorxpath)) {
|
||||
|
||||
$msgs = array();
|
||||
foreach ($phpmessages as $phpmessage) {
|
||||
@@ -279,7 +298,7 @@ class behat_hooks extends behat_base {
|
||||
// Any other backtrace.
|
||||
// First looking through xpath as it is faster than get and parse the whole page contents,
|
||||
// we get the contents and look for matches once we found something to suspect that there is a backtrace.
|
||||
if ($this->getSession()->getDriver()->find("(//html/descendant::*[contains(., ': call to ')])[1]")) {
|
||||
if ($this->getSession()->getDriver()->find($othersxpath)) {
|
||||
$backtracespattern = '/(line [0-9]* of [^:]*: call to [\->&;:a-zA-Z_\x7f-\xff][\->&;:a-zA-Z0-9_\x7f-\xff]*)/';
|
||||
if (preg_match_all($backtracespattern, $this->getSession()->getPage()->getContent(), $backtraces)) {
|
||||
$msgs = array();
|
||||
|
||||
@@ -56,16 +56,19 @@ class behat_navigation extends behat_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid problems with quotes.
|
||||
$nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
|
||||
|
||||
$xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/child::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]" .
|
||||
"|" .
|
||||
"//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed'))]" .
|
||||
"/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]";
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]";
|
||||
|
||||
$exception = new ExpectationException('The "' . $nodetext . '" node can not be expanded', $this->getSession());
|
||||
$node = $this->find('xpath', $xpath, $exception);
|
||||
@@ -86,15 +89,18 @@ class behat_navigation extends behat_base {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Avoid problems with quotes.
|
||||
$nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
|
||||
|
||||
$xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/child::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]" .
|
||||
"|" .
|
||||
"//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed'))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch')]" .
|
||||
"/child::span[contains(concat(' ', normalize-space(.), ' '), '" . $nodetext . "')]";
|
||||
"/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
|
||||
"/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
|
||||
"/child::span[normalize-space(.)=$nodetextliteral]";
|
||||
|
||||
$exception = new ExpectationException('The "' . $nodetext . '" node can not be collapsed', $this->getSession());
|
||||
$node = $this->find('xpath', $xpath, $exception);
|
||||
|
||||
@@ -52,14 +52,14 @@ class behat_permissions extends behat_base {
|
||||
|
||||
return array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I collapse "Front page settings" node'),
|
||||
new Given('I expand "Site administration" node'),
|
||||
new Given('I expand "Users" node'),
|
||||
new Given('I expand "Permissions" node'),
|
||||
new Given('I follow "Define roles"'),
|
||||
new Given('I collapse "' . get_string('frontpagesettings', 'admin') . '" node'),
|
||||
new Given('I expand "' . get_string('administrationsite') . '" node'),
|
||||
new Given('I expand "' . get_string('users', 'admin') . '" node'),
|
||||
new Given('I expand "' . get_string('permissions', 'role') . '" node'),
|
||||
new Given('I follow "' . get_string('defineroles', 'role') . '"'),
|
||||
new Given('I follow "Edit ' . $this->escape($rolename) . ' role"'),
|
||||
new Given('I fill the capabilities form with the following permissions:', $table),
|
||||
new Given('I press "Save changes"')
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -73,12 +73,12 @@ class behat_permissions extends behat_base {
|
||||
public function i_override_the_system_permissions_of_role_with($rolename, $table) {
|
||||
|
||||
// We don't know the number of overrides so we have to get it to match the option contents.
|
||||
$roleoption = $this->find('xpath', '//select[@name="roleid"]/option[contains(text(),"' . $this->escape($rolename) . '")]');
|
||||
$roleoption = $this->find('xpath', '//select[@name="roleid"]/option[contains(.,"' . $this->escape($rolename) . '")]');
|
||||
|
||||
return array(
|
||||
new Given('I select "' . $this->escape($roleoption->getText()) . '" from "Advanced role override"'),
|
||||
new Given('I select "' . $this->escape($roleoption->getText()) . '" from "' . get_string('advancedoverride', 'role') . '"'),
|
||||
new Given('I fill the capabilities form with the following permissions:', $table),
|
||||
new Given('I press "Save changes"')
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,9 +93,9 @@ class behat_permissions extends behat_base {
|
||||
// Ensure we are using the advanced view.
|
||||
// Wrapped in a try/catch to capture the exception and continue execution, we don't know if advanced mode was already enabled.
|
||||
try {
|
||||
$advancedtoggle = $this->find_button('Show advanced');
|
||||
$advancedtoggle = $this->find_button(get_string('showadvanced', 'form'));
|
||||
if ($advancedtoggle) {
|
||||
$this->getSession()->getPage()->pressButton('Show advanced');
|
||||
$this->getSession()->getPage()->pressButton(get_string('showadvanced', 'form'));
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
// We already are in advanced mode.
|
||||
|
||||
@@ -263,7 +263,14 @@ function profiling_urls($report, $runid, $runid2 = null) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
function profiling_print_run($run, $prevrunid = null) {
|
||||
/**
|
||||
* Generate the output to print a profiling run including further actions you can then take.
|
||||
*
|
||||
* @param object $run The profiling run object we are going to display.
|
||||
* @param array $prevreferences A list of run objects to list as comparison targets.
|
||||
* @return string The output to display on the screen for this run.
|
||||
*/
|
||||
function profiling_print_run($run, $prevreferences = null) {
|
||||
global $CFG, $OUTPUT;
|
||||
|
||||
$output = '';
|
||||
@@ -297,13 +304,28 @@ function profiling_print_run($run, $prevrunid = null) {
|
||||
// Add link to details
|
||||
$strviewdetails = get_string('viewdetails', 'tool_profiling');
|
||||
$url = profiling_urls('run', $run->runid);
|
||||
$output.=$OUTPUT->heading('<a href="' . $url . '" onclick="javascript:window.open(' . "'" . $url . "'" . ');' .
|
||||
'return false;"' . ' title="">' . $strviewdetails . '</a>', 3, 'main profilinglink');
|
||||
// If there is one previous run marked as reference, add link to diff
|
||||
if ($prevrunid) {
|
||||
$strviewdiff = get_string('viewdiff', 'tool_profiling');
|
||||
$url = 'index.php?runid=' . $run->runid . '&runid2=' . $prevrunid . '&listurl=' . urlencode($run->url);
|
||||
$output.=$OUTPUT->heading('<a href="' . $url . '" title="">' . $strviewdiff . '</a>', 3, 'main profilinglink');
|
||||
$output .= $OUTPUT->heading('<a href="' . $url . '" onclick="javascript:window.open(' . "'" . $url . "'" . ');' .
|
||||
'return false;"' . ' title="">' . $strviewdetails . '</a>', 3, 'main profilinglink');
|
||||
|
||||
// If there are previous run(s) marked as reference, add link to diff.
|
||||
if ($prevreferences) {
|
||||
$table = new html_table();
|
||||
$table->align = array('left', 'left');
|
||||
$table->head = array(get_string('date'), get_string('runid', 'tool_profiling'), get_string('comment', 'tool_profiling'));
|
||||
$table->tablealign = 'center';
|
||||
$table->attributes['class'] = 'flexible generaltable generalbox';
|
||||
$table->colclasses = array('value', 'value', 'value');
|
||||
$table->data = array();
|
||||
|
||||
$output .= $OUTPUT->heading(get_string('viewdiff', 'tool_profiling'), 3, 'main profilinglink');
|
||||
|
||||
foreach ($prevreferences as $reference) {
|
||||
$url = 'index.php?runid=' . $run->runid . '&runid2=' . $reference->runid . '&listurl=' . urlencode($run->url);
|
||||
$row = array(userdate($reference->timecreated), '<a href="' . $url . '" title="">'.$reference->runid.'</a>', $reference->runcomment);
|
||||
$table->data[] = $row;
|
||||
}
|
||||
$output .= $OUTPUT->box(html_writer::table($table), 'profilingrunbox', 'profiling_diffs', true);
|
||||
|
||||
}
|
||||
// Add link to export this run.
|
||||
$strexport = get_string('exportthis', 'tool_profiling');
|
||||
|
||||
@@ -63,14 +63,14 @@ class behat_message extends behat_base {
|
||||
$steps[] = new Given('I am on homepage');
|
||||
|
||||
if ($this->running_javascript()) {
|
||||
$steps[] = new Given('I expand "My profile" node');
|
||||
$steps[] = new Given('I expand "' . get_string('myprofile') . '" node');
|
||||
}
|
||||
|
||||
$steps[] = new Given('I follow "Messages"');
|
||||
$steps[] = new Given('I fill in "' . get_string('searchcombined', 'message') . '" with "' . $tofullname . '"');
|
||||
$steps[] = new Given('I follow "' . get_string('messages', 'message') . '"');
|
||||
$steps[] = new Given('I fill in "' . get_string('searchcombined', 'message') . '" with "' . $this->escape($tofullname) . '"');
|
||||
$steps[] = new Given('I press "' . get_string('searchcombined', 'message') . '"');
|
||||
$steps[] = new Given('I follow "' . get_string('sendmessageto', 'message', $tofullname) . '"');
|
||||
$steps[] = new Given('I fill in "id_message" with "' . $messagecontent . '"');
|
||||
$steps[] = new Given('I follow "' . $this->escape(get_string('sendmessageto', 'message', $tofullname)) . '"');
|
||||
$steps[] = new Given('I fill in "id_message" with "' . $this->escape($messagecontent) . '"');
|
||||
$steps[] = new Given('I press "' . get_string('sendmessage', 'message') . '"');
|
||||
|
||||
return $steps;
|
||||
|
||||
@@ -3394,7 +3394,7 @@ class assign {
|
||||
// Only show the grade if it is not hidden in gradebook.
|
||||
if (!empty($gradebookgrade->grade) && ($cangrade || !$gradebookgrade->hidden)) {
|
||||
if ($controller = $gradingmanager->get_active_controller()) {
|
||||
$controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
|
||||
$controller->set_grade_range(make_grades_menu($this->get_instance()->grade), $this->get_instance()->grade > 0);
|
||||
$gradefordisplay = $controller->render_grade($PAGE,
|
||||
$grade->id,
|
||||
$gradingitem,
|
||||
@@ -3491,7 +3491,7 @@ class assign {
|
||||
|
||||
// Now get the gradefordisplay.
|
||||
if ($controller) {
|
||||
$controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
|
||||
$controller->set_grade_range(make_grades_menu($this->get_instance()->grade), $this->get_instance()->grade > 0);
|
||||
$grade->gradefordisplay = $controller->render_grade($PAGE,
|
||||
$grade->id,
|
||||
$gradingitem,
|
||||
@@ -4880,6 +4880,7 @@ class assign {
|
||||
global $CFG, $USER;
|
||||
|
||||
$grademenu = make_grades_menu($this->get_instance()->grade);
|
||||
$allowgradedecimals = $this->get_instance()->grade > 0;
|
||||
|
||||
$advancedgradingwarning = false;
|
||||
$gradingmanager = get_grading_manager($this->context, 'mod_assign', 'submissions');
|
||||
@@ -4904,7 +4905,7 @@ class assign {
|
||||
}
|
||||
}
|
||||
if ($gradinginstance) {
|
||||
$gradinginstance->get_controller()->set_grade_range($grademenu);
|
||||
$gradinginstance->get_controller()->set_grade_range($grademenu, $allowgradedecimals);
|
||||
}
|
||||
return $gradinginstance;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,15 @@
|
||||
#input-message {background:#FFFFFF url(input.png) repeat-x scroll 0 0;padding:0 9px;border: 1px solid #999;border-radius: 9px;-moz-border-radius: 9px;}
|
||||
.mdl-chat-entry,
|
||||
.mdl-chat-my-entry {clear:both;}
|
||||
.dir-rtl .mdl-chat-entry,
|
||||
.dir-rtl .mdl-chat-my-entry {height: 90px;}
|
||||
|
||||
.chat-message .chat-message-meta {padding-top:15px;}
|
||||
.chat-message .picture {vertical-align:middle;}
|
||||
.chat-message .right {text-align:right;}
|
||||
.chat-message .left {text-align:left;}
|
||||
.dir-rtl .chat-message .right,
|
||||
.dir-rtl .chat-message .left {direction:ltr;}
|
||||
|
||||
#chat-input-area,
|
||||
#chat-input-area table.generaltable,
|
||||
|
||||
@@ -52,7 +52,7 @@ class behat_mod_choice extends behat_base {
|
||||
return array(
|
||||
new Given('I follow "' . $this->escape($choiceactivity) . '"'),
|
||||
new Given('I select "' . $this->escape($option) . '" radio button'),
|
||||
new Given('I press "Save my choice"')
|
||||
new Given('I press "' . get_string('savemychoice', 'choice') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ $string['page-mod-folder-view'] = 'Folder module main page';
|
||||
$string['pluginadministration'] = 'Folder administration';
|
||||
$string['pluginname'] = 'Folder';
|
||||
$string['display'] = 'Display folder contents';
|
||||
$string['display_help'] = 'If you choose to display the folder contents on a course page, there will be no link to a separate page and the title will not be displayed.
|
||||
$string['display_help'] = 'If you choose to display the folder contents on a course page, there will be no link to a separate page.
|
||||
The description will be displayed only if "Display description on course page" is checked.<br />
|
||||
Also note that participants view actions can not be logged in this case.';
|
||||
$string['displaypage'] = 'On a separate page';
|
||||
|
||||
@@ -58,7 +58,12 @@ class mod_folder_renderer extends plugin_renderer_base {
|
||||
}
|
||||
}
|
||||
|
||||
$output .= $this->output->box($this->render(new folder_tree($folder, $cm)),
|
||||
$foldertree = new folder_tree($folder, $cm);
|
||||
if ($folder->display == FOLDER_DISPLAY_INLINE) {
|
||||
// Display module name as the name of the root directory.
|
||||
$foldertree->dir['dirname'] = $cm->get_formatted_name();
|
||||
}
|
||||
$output .= $this->output->box($this->render($foldertree),
|
||||
'generalbox foldertree');
|
||||
|
||||
// Do not append the edit button on the course page.
|
||||
|
||||
@@ -51,9 +51,9 @@ class behat_mod_forum extends behat_base {
|
||||
// Escaping $forumname as it has been stripped automatically by the transformer.
|
||||
return array(
|
||||
new Given('I follow "' . $this->escape($forumname) . '"'),
|
||||
new Given('I press "' . get_string('addanewdiscussion', 'mod_forum') . '"'),
|
||||
new Given('I press "' . get_string('addanewdiscussion', 'forum') . '"'),
|
||||
new Given('I fill the moodle form with:', $table),
|
||||
new Given('I press "' . get_string('posttoforum', 'mod_forum') . '"'),
|
||||
new Given('I press "' . get_string('posttoforum', 'forum') . '"'),
|
||||
new Given('I wait to be redirected')
|
||||
);
|
||||
}
|
||||
@@ -71,9 +71,9 @@ class behat_mod_forum extends behat_base {
|
||||
return array(
|
||||
new Given('I follow "' . $this->escape($forumname) . '"'),
|
||||
new Given('I follow "' . $this->escape($postsubject) . '"'),
|
||||
new Given('I follow "' . get_string('reply', 'mod_forum') . '"'),
|
||||
new Given('I follow "' . get_string('reply', 'forum') . '"'),
|
||||
new Given('I fill the moodle form with:', $table),
|
||||
new Given('I press "' . get_string('posttoforum', 'mod_forum') . '"'),
|
||||
new Given('I press "' . get_string('posttoforum', 'forum') . '"'),
|
||||
new Given('I wait to be redirected')
|
||||
);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Feature: Set a certain number of discussions as a completion condition for a for
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I hover "//li[contains(concat(' ', @class, ' '), ' modtype_forum ')]/descendant::img[@alt='Not completed: Test forum name']" "xpath_element"
|
||||
Then I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_forum ')]/descendant::img[@alt='Not completed: Test forum name']" "xpath_element"
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Post 1 subject |
|
||||
| Message | Body 1 content |
|
||||
@@ -46,7 +46,7 @@ Feature: Set a certain number of discussions as a completion condition for a for
|
||||
| Subject | Post 2 subject |
|
||||
| Message | Body 2 content |
|
||||
And I follow "Course 1"
|
||||
And I hover "//li[contains(concat(' ', @class, ' '), ' modtype_forum ')]/descendant::img[contains(@alt, 'Completed: Test forum name')]" "xpath_element"
|
||||
And I hover "//li[contains(concat(' ', normalize-space(@class), ' '), ' modtype_forum ')]/descendant::img[contains(@alt, 'Completed: Test forum name')]" "xpath_element"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
|
||||
@@ -50,7 +50,7 @@ class behat_mod_glossary extends behat_base {
|
||||
return array(
|
||||
new Given('I press "' . get_string('addentry', 'mod_glossary') . '"'),
|
||||
new Given('I fill the moodle form with:', $data),
|
||||
new Given('I press "Save changes"')
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ class behat_mod_glossary extends behat_base {
|
||||
return array(
|
||||
new Given('I follow "' . get_string('categoryview', 'mod_glossary') . '"'),
|
||||
new Given('I press "' . get_string('editcategories', 'mod_glossary') . '"'),
|
||||
new Given('I press "Add Category"'),
|
||||
new Given('I fill in "name" with "' . $categoryname . '"'),
|
||||
new Given('I press "' . get_string('add').' '.get_string('category', 'glossary') . '"'),
|
||||
new Given('I fill in "name" with "' . $this->escape($categoryname) . '"'),
|
||||
new Given('I press "' . get_string('savechanges') . '"'),
|
||||
new Given('I press "' . get_string('back', 'mod_glossary') . '"')
|
||||
);
|
||||
|
||||
@@ -34,7 +34,7 @@ Feature: A teacher can choose whether to provide a printer-friendly glossary ent
|
||||
| Concept | Just a test concept |
|
||||
| Definition | Concept definition |
|
||||
Then "Printer-friendly version" "link" should exists
|
||||
And "//*[contains(concat(' ', @class, ' '), ' printicon ')]/descendant::a[contains(@href, 'print.php')]" "xpath_element" should exists
|
||||
And "//span[contains(concat(' ', normalize-space(@class), ' '), ' printicon ')]/descendant::a[contains(@href, 'print.php')]" "xpath_element" should exists
|
||||
And I follow "Printer-friendly version"
|
||||
And I should see "Just a test concept"
|
||||
|
||||
@@ -51,4 +51,4 @@ Feature: A teacher can choose whether to provide a printer-friendly glossary ent
|
||||
| Concept | Just a test concept |
|
||||
| Definition | Concept definition |
|
||||
Then "Printer-friendly version" "link" should not exists
|
||||
And "//*[contains(concat(' ', @class, ' '), ' printicon ')]/descendant::a[contains(@href, 'print.php')]" "xpath_element" should not exists
|
||||
And "//span[contains(concat(' ', normalize-space(@class), ' '), ' printicon ')]/descendant::a[contains(@href, 'print.php')]" "xpath_element" should not exists
|
||||
|
||||
@@ -40,7 +40,7 @@ Feature: In a lesson activity, students can navigate through a series of pages i
|
||||
| id_jumpto_1 | Next page |
|
||||
And I press "Save page"
|
||||
And I follow "Expanded"
|
||||
And I click on "Add a question page here" "link" in the "//div[contains(concat(' ', @class, ' '), ' addlinks ')][3]" "xpath_element"
|
||||
And I click on "Add a question page here" "link" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' addlinks ')][3]" "xpath_element"
|
||||
And I select "Numerical" from "Select a question type"
|
||||
And I press "Add a question page"
|
||||
And I fill the moodle form with:
|
||||
|
||||
@@ -66,7 +66,7 @@ class quiz_statistics_question_table extends flexible_table {
|
||||
|
||||
$this->define_baseurl($reporturl->out());
|
||||
$this->collapsible(false);
|
||||
$this->set_attribute('class', 'generaltable generalbox boxaligncenter');
|
||||
$this->set_attribute('class', 'generaltable generalbox boxaligncenter quizresponseanalysis');
|
||||
|
||||
// Define the table columns.
|
||||
$columns = array();
|
||||
|
||||
@@ -416,6 +416,14 @@ table.quizreviewsummary td.cell {
|
||||
#page-mod-quiz-report fieldset.felement.fgroup {
|
||||
margin: 0;
|
||||
}
|
||||
#page-mod-quiz-report table th {
|
||||
white-space: normal;
|
||||
}
|
||||
#page-mod-quiz-report table#attempts td,
|
||||
#page-mod-quiz-report table.quizresponseanalysis td {
|
||||
word-wrap: break-word;
|
||||
max-width: 20em;
|
||||
}
|
||||
#page-mod-quiz-report table.titlesleft td.c0 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -2169,11 +2169,17 @@ class page_wiki_confirmrestore extends page_wiki_save {
|
||||
|
||||
class page_wiki_prettyview extends page_wiki {
|
||||
|
||||
function print_header() {
|
||||
global $CFG, $PAGE, $OUTPUT;
|
||||
function __construct($wiki, $subwiki, $cm) {
|
||||
global $PAGE;
|
||||
$PAGE->set_pagelayout('embedded');
|
||||
echo $OUTPUT->header();
|
||||
parent::__construct($wiki, $subwiki, $cm);
|
||||
}
|
||||
|
||||
function print_header() {
|
||||
global $OUTPUT;
|
||||
$this->set_url();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo '<h1 id="wiki_printable_title">' . format_string($this->title) . '</h1>';
|
||||
}
|
||||
|
||||
|
||||
@@ -51,16 +51,18 @@ class behat_question extends behat_base {
|
||||
*/
|
||||
public function i_add_a_question_filling_the_form_with($questiontypename, TableNode $questiondata) {
|
||||
|
||||
$questiontypexpath = "//span[@class='qtypename'][.='" . $questiontypename . "']" .
|
||||
// Using xpath literal to avoid quotes problems.
|
||||
$questiontypename = $this->getSession()->getSelectorsHandler()->xpathLiteral($questiontypename);
|
||||
$questiontypexpath = "//span[@class='qtypename'][normalize-space(.)=$questiontypename]" .
|
||||
"/ancestor::div[@class='qtypeoption']/descendant::input";
|
||||
|
||||
return array(
|
||||
new Given('I follow "' . get_string('questionbank', 'question') . '"'),
|
||||
new Given('I press "' . get_string('createnewquestion', 'question') . '"'),
|
||||
new Given('I click on "' . $questiontypexpath . '" "xpath_element"'),
|
||||
new Given('I click on "' . $this->escape($questiontypexpath) . '" "xpath_element"'),
|
||||
new Given('I click on "Next" "button" in the "#qtypechoicecontainer" "css_element"'),
|
||||
new Given('I fill the moodle form with:', $questiondata),
|
||||
new Given('I press "Save changes"')
|
||||
new Given('I press "' . get_string('savechanges') . '"')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,14 +77,18 @@ class behat_question extends behat_base {
|
||||
*/
|
||||
public function the_state_of_question_is_shown_as($questiondescription, $state) {
|
||||
|
||||
// Using xpath literal to avoid quotes problems.
|
||||
$questiondescriptionliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($questiondescription);
|
||||
$stateliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($state);
|
||||
|
||||
// Split in two checkings to give more feedback in case of exception.
|
||||
$exception = new ElementNotFoundException($this->getSession(), 'Question "' . $questiondescription . '" ');
|
||||
$questionxpath = "//div[contains(concat(' ', @class, ' '), ' qtext ')][contains(., '" . $questiondescription . "')]";
|
||||
$questionxpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' qtext ')][contains(., $questiondescriptionliteral)]";
|
||||
$this->find('xpath', $questionxpath, $exception);
|
||||
|
||||
$exception = new ExpectationException('Question "' . $questiondescription . '" state is not "' . $state . '"', $this->getSession());
|
||||
$xpath = $questionxpath . "/ancestor::div[contains(concat(' ', @class, ' '), ' que ')]" .
|
||||
"/descendant::div[@class='state'][contains(., '" . $state . "')]";
|
||||
$xpath = $questionxpath . "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' que ')]" .
|
||||
"/descendant::div[@class='state'][contains(., $stateliteral)]";
|
||||
$this->find('xpath', $xpath, $exception);
|
||||
}
|
||||
|
||||
|
||||
@@ -94,6 +94,7 @@ if ($requestedqtype) {
|
||||
JOIN {question_categories} qc ON q.category = qc.id
|
||||
JOIN {context} con ON con.id = qc.contextid
|
||||
$sqlqtypetest
|
||||
AND (q.parent = 0 OR q.parent = q.id)
|
||||
GROUP BY qc.contextid, $ctxgroupby
|
||||
ORDER BY numquestions DESC, numhidden ASC, con.contextlevel ASC, con.id ASC", $params);
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ class behat_repository_recent extends behat_files {
|
||||
// Opening the specified file contextual menu from the modal window.
|
||||
$this->open_element_contextual_menu($filename);
|
||||
|
||||
$this->find_button('Select this file')->click();
|
||||
$this->find_button(get_string('getfile', 'repository'))->click();
|
||||
|
||||
// Ensure the file has been selected and we returned to the form page.
|
||||
$this->wait_until_return_to_form();
|
||||
|
||||
@@ -63,7 +63,7 @@ class behat_filepicker extends behat_files {
|
||||
$dialoginput = $this->find('css', '.fp-mkdir-dlg-text input');
|
||||
$dialoginput->setValue($foldername);
|
||||
|
||||
$this->getSession()->getPage()->pressButton('Create folder');
|
||||
$this->getSession()->getPage()->pressButton(get_string('makeafolder'));
|
||||
|
||||
// Wait until the process finished and modal windows are hidden.
|
||||
$this->wait_until_return_to_form();
|
||||
@@ -92,6 +92,8 @@ class behat_filepicker extends behat_files {
|
||||
// Just in case there is any contents refresh in progress.
|
||||
$this->wait_until_contents_are_updated($fieldnode);
|
||||
|
||||
$folderliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($foldername);
|
||||
|
||||
// We look both in the pathbar and in the contents.
|
||||
try {
|
||||
|
||||
@@ -99,8 +101,8 @@ class behat_filepicker extends behat_files {
|
||||
$folder = $this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' fp-folder ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' fp-filename ')]" .
|
||||
"[normalize-space(.)='" . $foldername . "']",
|
||||
"/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-filename ')]" .
|
||||
"[normalize-space(.)=$folderliteral]",
|
||||
$exception,
|
||||
$fieldnode
|
||||
);
|
||||
@@ -110,7 +112,7 @@ class behat_filepicker extends behat_files {
|
||||
$folder = $this->find(
|
||||
'xpath',
|
||||
"//a[contains(concat(' ', normalize-space(@class), ' '), ' fp-path-folder-name ')]" .
|
||||
"[normalize-space(.)='" . $foldername . "']",
|
||||
"[normalize-space(.)=$folderliteral]",
|
||||
$exception,
|
||||
$fieldnode
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ Feature: A selected file can be cancelled
|
||||
And I upload "lib/tests/fixtures/upload_users.csv" file to "Files" filepicker
|
||||
And I click on "#fitem_id_files .fp-btn-add a" "css_element"
|
||||
And I click on "Recent files" "link" in the ".fp-repo-area" "css_element"
|
||||
And I click on "//a[contains(concat(' ', @class, ' '), ' fp-file ')][contains(., 'empty.txt')]" "xpath_element"
|
||||
And I click on "//a[contains(concat(' ', normalize-space(@class), ' '), ' fp-file ')][normalize-space(.)='empty.txt']" "xpath_element"
|
||||
And I click on ".yui3-panel-focused .fp-select .fp-select-cancel" "css_element"
|
||||
And I click on ".yui3-panel-focused .file-picker button.yui3-button-close" "css_element"
|
||||
And I press "Save and display"
|
||||
|
||||
@@ -65,10 +65,10 @@ class behat_repository_upload extends behat_files {
|
||||
$noformexception = new ExpectationException('The upload file form is not ready', $this->getSession());
|
||||
$this->find(
|
||||
'xpath',
|
||||
"//div[contains(concat(' ', @class, ' '), ' file-picker ')]" .
|
||||
"[contains(concat(' ', @class, ' '), ' repository_upload ')]" .
|
||||
"//div[contains(concat(' ', normalize-space(@class), ' '), ' file-picker ')]" .
|
||||
"[contains(concat(' ', normalize-space(@class), ' '), ' repository_upload ')]" .
|
||||
"/descendant::div[@class='fp-content']" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' fp-upload-form ')]" .
|
||||
"/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' fp-upload-form ')]" .
|
||||
"/descendant::form",
|
||||
$noformexception
|
||||
);
|
||||
|
||||
@@ -418,7 +418,10 @@ img.iconsmall {
|
||||
margin-right: 0.5em;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.dir-rtl .form-item .form-setting .defaultsnext {
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0;
|
||||
}
|
||||
.form-item .form-setting .locked-checkbox {
|
||||
margin-right: 0.2em;
|
||||
margin-left: 0.5em;
|
||||
|
||||
@@ -1330,7 +1330,7 @@ audio.mediaplugin_html5audio {
|
||||
background-position: 0 -8866px;
|
||||
}
|
||||
.dir-rtl.yui-skin-sam .yui-panel .hd {
|
||||
text-align: left;
|
||||
text-align: right;
|
||||
}
|
||||
.dir-rtl .yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd {
|
||||
text-align: right;
|
||||
@@ -1905,4 +1905,4 @@ div.badge .expireimage {
|
||||
}
|
||||
.breadcrumb-nav .breadcrumb {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,32 @@ table.flexible,
|
||||
.generaltable {
|
||||
.table-striped;
|
||||
}
|
||||
|
||||
.dir-rtl {
|
||||
table#explaincaps,
|
||||
table#defineroletable,
|
||||
table.grading-report,
|
||||
table#listdirectories,
|
||||
table.rolecaps,
|
||||
table.userenrolment,
|
||||
table#form,
|
||||
form#movecourses table,
|
||||
.forumheaderlist,
|
||||
table.flexible,
|
||||
.generaltable,
|
||||
.generaltable thead:first-child tr:first-child {
|
||||
td , th {
|
||||
text-align:right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#page-admin-course-index.dir-rtl .editcourse {
|
||||
td , th {
|
||||
text-align:right;
|
||||
}
|
||||
}
|
||||
|
||||
#page-report-loglive-index .generaltable,
|
||||
#page-admin-report-log-index .generaltable,
|
||||
#page-report-log-user .generaltable,
|
||||
|
||||
@@ -432,6 +432,7 @@
|
||||
width: 17px;
|
||||
height: 22px;
|
||||
}
|
||||
.dir-rtl .filemanager .ygtvtn,
|
||||
.dir-rtl .file-picker .ygtvtn {
|
||||
background: url('[[pix:moodle|y/tn_rtl]]') 0 0 no-repeat;
|
||||
width: 17px;
|
||||
|
||||
@@ -150,6 +150,12 @@ input#id_externalurl {
|
||||
.mform .fitem div.fitemtitle {
|
||||
.form-horizontal .control-label
|
||||
}
|
||||
.dir-rtl {
|
||||
.form-item .form-label,
|
||||
.mform .fitem div.fitemtitle {
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
.form-defaultinfo,
|
||||
.form-label .form-shortname {
|
||||
.muted;
|
||||
@@ -341,6 +347,9 @@ input[type="checkbox"] {
|
||||
.form-item .form-label label {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.dir-rtl .form-item .form-label label {
|
||||
text-align:left;
|
||||
}
|
||||
.felement.ffilepicker {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
@@ -548,7 +548,12 @@ table#user-grades tr.controls td,
|
||||
.path-grade-report-grader table td.userfield {
|
||||
text-align:left;
|
||||
}
|
||||
|
||||
.path-grade-report-grader.dir-rtl {
|
||||
table th.user,
|
||||
table td.userfield {
|
||||
text-align:right;
|
||||
}
|
||||
}
|
||||
.path-grade-report-grader .usersuspended a:link,
|
||||
.path-grade-report-grader .usersuspended a:visited {
|
||||
.muted
|
||||
@@ -592,3 +597,12 @@ table#user-grades tr.controls td,
|
||||
.path-grade-report-grader #hiddentooltiproot, .tooltipDiv {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gradingform_rubric.editor .criteria .definition textarea,
|
||||
.gradingform_rubric.editor .criteria .scorevalue input {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.gradingform_rubric.editor .criteria .scorevalue input {
|
||||
float: left;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
#chooseqtype .qtypename img {
|
||||
padding: 0 0.3em;
|
||||
}
|
||||
#chooseqtype .qtypename {
|
||||
display: inline-table;
|
||||
width: 16em;
|
||||
}
|
||||
#chooseqtype .qtypesummary {
|
||||
display: block;
|
||||
margin: 0 2em;
|
||||
@@ -60,7 +64,7 @@
|
||||
}
|
||||
//#qtypechoicecontainer
|
||||
#chooseqtype {
|
||||
width: 35em;
|
||||
width: 40em;
|
||||
}
|
||||
#chooseqtypehead h3 {
|
||||
margin: 0;
|
||||
@@ -95,6 +99,7 @@
|
||||
margin: 0;
|
||||
padding: 1.5em 1.6em;
|
||||
background-color: #fff;
|
||||
overflow-y: auto;
|
||||
}
|
||||
#chooseqtype .instruction,
|
||||
#chooseqtype .selected .qtypesummary {
|
||||
|
||||
@@ -33,6 +33,19 @@
|
||||
.form-horizontal .controls {
|
||||
margin-left: @horizontalComponentOffset980;
|
||||
}
|
||||
.dir-rtl {
|
||||
.form-item .form-setting,
|
||||
.form-item .form-description,
|
||||
.mform .fitem .felement,
|
||||
.mform .fdescription.required,
|
||||
.userprofile dl.list dd,
|
||||
.form-horizontal .controls {
|
||||
margin-right: @horizontalComponentOffset980;
|
||||
}
|
||||
}
|
||||
#page-mod-forum-search.dir-lrt .c1 {
|
||||
margin-right: @horizontalComponentOffset980;
|
||||
}
|
||||
.path-admin .buttons,
|
||||
.form-buttons {
|
||||
padding-left: @horizontalComponentOffset980;
|
||||
@@ -66,10 +79,29 @@
|
||||
.form-horizontal .controls {
|
||||
margin-left: @horizontalComponentOffset1200;
|
||||
}
|
||||
.dir-rtl {
|
||||
.form-item .form-setting,
|
||||
.form-item .form-description,
|
||||
.mform .fitem .felement,
|
||||
.mform .fdescription.required,
|
||||
.userprofile dl.list dd,
|
||||
.form-horizontal .controls {
|
||||
margin-right: @horizontalComponentOffset1200;
|
||||
}
|
||||
#page-mod-forum-search .c1 {
|
||||
margin-right: @horizontalComponentOffset1200;
|
||||
}
|
||||
}
|
||||
.path-admin .buttons,
|
||||
.form-buttons {
|
||||
padding-left: @horizontalComponentOffset1200;
|
||||
}
|
||||
.dir-rtl {
|
||||
.path-admin .buttons,
|
||||
.form-buttons {
|
||||
padding-right: @horizontalComponentOffset1200;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+13
-9
@@ -97,11 +97,11 @@ if (!empty($CFG->enabledevicedetection) && empty($device)) {
|
||||
$table->head = array(get_string('devicetype', 'admin'), get_string('currenttheme', 'admin'), get_string('info'));
|
||||
|
||||
$devices = get_device_type_list();
|
||||
foreach ($devices as $device) {
|
||||
foreach ($devices as $thedevice) {
|
||||
|
||||
$headingthemename = ''; // To output the picked theme name when needed
|
||||
$themename = get_selected_theme_for_device_type($device);
|
||||
if (!$themename && $device == 'default') {
|
||||
$themename = get_selected_theme_for_device_type($thedevice);
|
||||
if (!$themename && $thedevice == 'default') {
|
||||
$themename = theme_config::DEFAULT_THEME;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ if (!empty($CFG->enabledevicedetection) && empty($device)) {
|
||||
$themename = clean_param($themename, PARAM_THEME);
|
||||
if (empty($themename)) {
|
||||
// Likely the theme has been deleted
|
||||
unset_config(get_device_cfg_var_name($device));
|
||||
unset_config(get_device_cfg_var_name($thedevice));
|
||||
} else {
|
||||
$strthemename = get_string('pluginname', 'theme_'.$themename);
|
||||
// link to the screenshot, now mandatory - the image path is hardcoded because we need image from other themes, not the current one
|
||||
@@ -123,19 +123,19 @@ if (!empty($CFG->enabledevicedetection) && empty($device)) {
|
||||
$headingthemename = $OUTPUT->heading($strthemename, 3);
|
||||
}
|
||||
// If not default device then show option to unset theme.
|
||||
if ($device != 'default') {
|
||||
if ($thedevice != 'default') {
|
||||
$unsetthemestr = get_string('unsettheme', 'admin');
|
||||
$unsetthemeurl = new moodle_url('/theme/index.php', array('device' => $device, 'sesskey' => sesskey(), 'unsettheme' => true));
|
||||
$unsetthemeurl = new moodle_url('/theme/index.php', array('device' => $thedevice, 'sesskey' => sesskey(), 'unsettheme' => true));
|
||||
$unsetthemebutton = new single_button($unsetthemeurl, $unsetthemestr, 'get');
|
||||
$unsetthemebutton = $OUTPUT->render($unsetthemebutton);
|
||||
}
|
||||
}
|
||||
|
||||
$deviceurl = new moodle_url('/theme/index.php', array('device' => $device, 'sesskey' => sesskey()));
|
||||
$deviceurl = new moodle_url('/theme/index.php', array('device' => $thedevice, 'sesskey' => sesskey()));
|
||||
$select = new single_button($deviceurl, $strthemeselect, 'get');
|
||||
|
||||
$table->data[] = array(
|
||||
$OUTPUT->heading(ucfirst($device), 3),
|
||||
$OUTPUT->heading(ucfirst($thedevice), 3),
|
||||
$screenshotcell,
|
||||
$headingthemename . $OUTPUT->render($select) . $unsetthemebutton
|
||||
);
|
||||
@@ -217,7 +217,11 @@ if (!empty($CFG->enabledevicedetection) && empty($device)) {
|
||||
echo $OUTPUT->header('themeselector');
|
||||
echo $OUTPUT->heading($heading);
|
||||
|
||||
echo $OUTPUT->single_button(new moodle_url('index.php', array('sesskey' => sesskey(), 'reset' => 1, 'device' => $device)), get_string('themeresetcaches', 'admin'));
|
||||
$params = array('sesskey' => sesskey(), 'reset' => 1);
|
||||
if (!empty($device)) {
|
||||
$params['device'] = $device;
|
||||
}
|
||||
echo $OUTPUT->single_button(new moodle_url('index.php', $params), get_string('themeresetcaches', 'admin'));
|
||||
|
||||
echo html_writer::table($table);
|
||||
|
||||
|
||||
+2
-2
@@ -29,11 +29,11 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2013051401.04; // 20130514 = branching date YYYYMMDD - do not modify!
|
||||
$version = 2013051401.06; // 20130514 = branching date YYYYMMDD - do not modify!
|
||||
// RR = release increments - 00 in DEV branches
|
||||
// .XX = incremental changes
|
||||
|
||||
$release = '2.5.1+ (Build: 20130719)'; // Human-friendly version name
|
||||
$release = '2.5.1+ (Build: 20130726)'; // Human-friendly version name
|
||||
|
||||
$branch = '25'; // this version's branch
|
||||
$maturity = MATURITY_STABLE; // this version's maturity level
|
||||
|
||||
Reference in New Issue
Block a user