if ($confirmed or $isios) {
$PAGE->set_context(context_system::instance());
$PAGE->set_heading($COURSE->fullname);
- $PAGE->set_url('/local/mobile/launch.php', array('service' => $serviceshortname, 'passport' => $passport, 'urlscheme' => $urlscheme));
+ $params = array('service' => $serviceshortname, 'passport' => $passport, 'urlscheme' => $urlscheme, 'confirmed' => $confirmed);
+ $PAGE->set_url("/$CFG->admin/tool/mobile/launch.php", $params);
echo $OUTPUT->header();
if ($confirmed) {
*/
Tour.prototype.tourName;
+/**
+ * The name of the tour storage key.
+ *
+ * @property {String} storageKey
+ */
+Tour.prototype.storageKey;
+
+/**
+ * The session storage object
+ *
+ * @property {Storage} storage
+ */
+Tour.prototype.storage;
+
/**
* The original configuration as passed into the constructor.
*
// Apply configuration.
this.configure.apply(this, arguments);
+ try {
+ this.storage = window.sessionStorage;
+ this.storageKey = 'tourstate_' + this.tourName;
+ } catch (e) {
+ this.storage = false;
+ this.storageKey = '';
+ }
+
return this;
};
*/
Tour.prototype.setCurrentStepNumber = function (stepNumber) {
this.currentStepNumber = stepNumber;
+ if (this.storage) {
+ try {
+ this.storage.setItem(this.storageKey, stepNumber);
+ } catch (e) {
+ if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+ this.storage.removeItem(this.storageKey);
+ }
+ }
+ }
};
/**
* @chainable
*/
Tour.prototype.startTour = function (startAt) {
+ if (this.storage && typeof startAt === 'undefined') {
+ var storageStartValue = this.storage.getItem(this.storageKey);
+ if (storageStartValue) {
+ var storageStartAt = parseInt(storageStartValue, 10);
+ if (storageStartAt <= this.steps.length) {
+ startAt = storageStartAt;
+ }
+ }
+ }
+
if (typeof startAt === 'undefined') {
startAt = this.getCurrentStepNumber();
}
/**
* Fetch all enabled tours matching the specified target.
*
- * @param string $targetmatch The URL to match.
+ * @param moodle_url $targetmatch The URL to match.
*/
- public static function get_matching_tourdata($targetmatch) {
+ public static function get_matching_tourdata(\moodle_url $targetmatch) {
$tours = self::get_enabled_tourdata();
- return array_filter($tours, function($tour) use ($targetmatch) {
+ // Attempt to determine whether this is the front page.
+ // This is a special case because the frontpage uses a shortened page path making it difficult to detect exactly.
+ $isfrontpage = $targetmatch->compare(new \moodle_url('/'), URL_MATCH_BASE);
+ $target = $targetmatch->out_as_local_url();
+ return array_filter($tours, function($tour) use ($isfrontpage, $target) {
+ if ($isfrontpage && $tour->pathmatch === 'FRONTPAGE') {
+ return true;
+ }
$pattern = preg_quote($tour->pathmatch, '@');
$pattern = str_replace('%', '.*', $pattern);
- return !!preg_match("@{$pattern}@", $targetmatch);
+ return !!preg_match("@{$pattern}@", $target);
});
}
public static function get_matching_tours(\moodle_url $pageurl) {
global $PAGE;
- $tours = cache::get_matching_tourdata($pageurl->out_as_local_url());
+ $tours = cache::get_matching_tourdata($pageurl);
foreach ($tours as $record) {
$tour = tour::load_from_record($record);
* This is used in the session cookie to determine whether the user has seen this tour before.
*/
public function get_tour_key() {
+ global $USER;
+
$tourtime = $this->get_config('majorupdatetime', null);
if ($tourtime === null) {
$tourtime = max($tourtime, $userresetdate);
}
- return sprintf('tool_usertours_%d_%s', $this->get_id(), $tourtime);
+ return sprintf('tool_usertours_%d_%d_%s', $USER->id, $this->get_id(), $tourtime);
}
/**
* /my/% - to match the Dashboard
* /course/view.php?id=2 - to match a specific course
* /mod/forum/view.php% - to match the forum discussion list
-* /user/profile.php% - to match the user profile page';
+* /user/profile.php% - to match the user profile page
+
+If you wish to display a tour on the Site Home page, you can use the value: "FRONTPAGE".
+';
$string['placement'] = 'Placement';
$string['pluginname'] = 'User tours';
$string['resettouronpage'] = 'Reset user tour on this page';
'name' => 'my_glob_2',
'pathmatch' => '/my/%'
],
+ (object) [
+ 'name' => 'frontpage_only',
+ 'pathmatch' => 'FRONTPAGE'
+ ],
+ (object) [
+ 'name' => 'frontpage_match',
+ 'pathmatch' => '/?%'
+ ],
];
return [
'/my/view.php',
['my_exact_1', 'my_glob_1', 'my_glob_2'],
],
+ 'Special constant FRONTPAGE must match front page only' => [
+ $tourconfigs,
+ '/',
+ ['frontpage_only'],
+ ],
+ 'Standard frontpage URL matches both the special constant, and a correctly formed pathmatch' => [
+ $tourconfigs,
+ '/?redirect=0',
+ ['frontpage_only', 'frontpage_match'],
+ ],
];
}
$this->helper_create_step((object) ['tourid' => $tour->get_id()]);
}
- $matches = \tool_usertours\cache::get_matching_tourdata((new moodle_url($targetmatch))->out_as_local_url());
+ $matches = \tool_usertours\cache::get_matching_tourdata(new moodle_url($targetmatch));
$this->assertCount(count($expected), $matches);
for ($i = 0; $i < count($matches); $i++) {
$this->greaterThanOrEqual($time),
true,
null,
- sprintf('tool_usertours_%d_%s', $id, $time),
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
],
'Initial tour time, no user pref' => [
null,
false,
null,
- sprintf('tool_usertours_%d_%s', $id, $time),
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
],
'Initial tour time, with user reset lower' => [
$id,
null,
false,
$time - DAYSECS,
- sprintf('tool_usertours_%d_%s', $id, $time),
+ sprintf('tool_usertours_\d_%d_%s', $id, $time),
],
'Initial tour time, with user reset higher' => [
$id,
null,
false,
$time + DAYSECS,
- sprintf('tool_usertours_%d_%s', $id, $time + DAYSECS),
+ sprintf('tool_usertours_\d_%d_%s', $id, $time + DAYSECS),
],
];
}
set_user_preference(\tool_usertours\tour::TOUR_REQUESTED_BY_USER . $id, $userpref);
}
- $this->assertEquals(
- $expectation,
+ $this->assertRegExp(
+ '/' . $expectation . '/',
$tour->get_tour_key()
);
}
<location>amd/src/tour.js</location>
<name>Flexitour</name>
<license>GPLv3</license>
- <version>0.9.9</version>
+ <version>0.9.10</version>
<licenseversion>3</licenseversion>
</library>
<library>
)
), 'User custom fields (also known as user profile fields)', VALUE_DEFAULT, array()
),
- 'redirect' => new external_value(PARAM_URL, 'Redirect the user to this url after confirmation.', VALUE_DEFAULT, ''),
+ 'redirect' => new external_value(PARAM_LOCALURL, 'Redirect the user to this site url after confirmation.',
+ VALUE_DEFAULT, ''),
)
);
}
* @param string $recaptchachallengehash recaptcha challenge hash
* @param string $recaptcharesponse recaptcha response
* @param array $customprofilefields user custom fields (also known as user profile fields)
- * @param string $redirect Url to redirect the user after confirmation
+ * @param string $redirect Site url to redirect the user after confirmation
* @return array settings and possible warnings
* @since Moodle 3.2
* @throws moodle_exception
* @Given /^I log out$/
*/
public function i_log_out() {
- // There is no longer any need to worry about whether the navigation
- // bar needs to be expanded; user_menu now lives outside the
- // hamburger.
-
- // However, the user menu *always* needs to be expanded. if running JS.
- if ($this->running_javascript()) {
- $xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
-
- $this->execute('behat_general::i_click_on', array($xpath, "xpath_element"));
- }
-
- // No need to check for exceptions as it will checked after this step execution.
- $this->execute('behat_general::click_link', get_string('logout'));
+ // Click on logout link in footer, as it's much faster.
+ $this->execute('behat_general::i_click_on_in_the', array(get_string('logout'), 'link', '#page-footer', "css_element"));
}
}
}
$data->contextid = $mapping->parentitemid;
+ // Before 3.1, the 'stamp' field could be erroneously duplicated.
+ // From 3.1 onwards, there's a unique index of (contextid, stamp).
+ // If we encounter a duplicate in an old restore file, just generate a new stamp.
+ // This is the same as what happens during an upgrade to 3.1+ anyway.
+ if ($DB->record_exists('question_categories', ['stamp' => $data->stamp, 'contextid' => $data->contextid])) {
+ $data->stamp = make_unique_id_code();
+ }
+
// Let's create the question_category and save mapping
$newitemid = $DB->insert_record('question_categories', $data);
$this->set_mapping('question_category', $oldid, $newitemid);
$locked = $uselocks && (get_config('backup', $config.'_locked') == true);
if ($plan->setting_exists($settingname)) {
$setting = $plan->get_setting($settingname);
- if ($setting->get_value() != $value || 1==1) {
+ // We can only update the setting if it isn't already locked by config or permission.
+ if ($setting->get_status() !== base_setting::LOCKED_BY_CONFIG
+ && $setting->get_status() !== base_setting::LOCKED_BY_PERMISSION) {
$setting->set_value($value);
if ($locked) {
$setting->set_status(base_setting::LOCKED_BY_CONFIG);
$context = context_course::instance($this->page->course->id);
$this->page->course->summary = file_rewrite_pluginfile_urls($this->page->course->summary, 'pluginfile.php', $context->id, 'course', 'summary', NULL);
$this->content->text = format_text($this->page->course->summary, $this->page->course->summaryformat, $options);
- if ($this->page->user_is_editing()) {
- if($this->page->course->id == SITEID) {
- $editpage = $CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=frontpagesettings';
- } else {
- $editpage = $CFG->wwwroot.'/course/edit.php?id='.$this->page->course->id;
- }
- $this->content->text .= "<div class=\"editbutton\"><a href=\"$editpage\"><img src=\"" . $OUTPUT->pix_url('t/edit') . "\" alt=\"".get_string('edit')."\" /></a></div>";
- }
$this->content->footer = '';
return $this->content;
And I should see "Course summary" in the "Course summary" "block"
And I should see "Proved the course summary block works!" in the "Course summary" "block"
- Scenario: Teacher can see an edit icon when edit mode is on and follow it to the course edit page
- When I log in as "teacher1"
- And I follow "Course 1"
- And I turn editing mode on
- Then I should see "Proved the course summary block works!" in the "Course summary" "block"
- And I should see "Course summary" in the "Course summary" "block"
- And I click on ".editbutton a" "css_element" in the "Course summary" "block"
- Then I should see "Edit course settings" in the "h2" "css_element"
-
Scenario: Teacher can not see edit icon when edit mode is off
When I log in as "teacher1"
And I follow "Course 1"
And I should not see "Course summary" in the "Course/site summary" "block"
And I should see "Proved the summary block works!" in the "Course/site summary" "block"
- Scenario: Admin can see an edit icon when edit mode is on and follow it to the front page settings
- When I log in as "admin"
- And I am on site homepage
- And I follow "Turn editing on"
- Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
- And I should not see "Course summary" in the "Course/site summary" "block"
- And I click on ".editbutton a" "css_element" in the "Course/site summary" "block"
- Then I should see "Front page settings" in the "h2" "css_element"
-
Scenario: Admin can not see edit icon when edit mode is off
When I log in as "admin"
And I am on site homepage
} else {
$imgalttext = get_string("completion-alt-auto-y", 'core_completion', $activityname);
}
- $csselementforactivitytype = "li.modtype_".strtolower($activitytype);
+ $activityxpath = "//li[contains(concat(' ', @class, ' '), ' modtype_" . strtolower($activitytype) . " ')]";
+ $activityxpath .= "[descendant::*[contains(text(), '" . $activityname . "')]]";
$xpathtocheck = "//img[contains(@alt, '$imgalttext')]";
$this->execute("behat_general::should_exist_in_the",
- array($xpathtocheck, "xpath_element", $csselementforactivitytype, "css_element")
+ array($xpathtocheck, "xpath_element", $activityxpath, "xpath_element")
);
}
} else {
$imgalttext = get_string("completion-alt-auto-n", 'core_completion', $activityname);
}
- $csselementforactivitytype = "li.modtype_".strtolower($activitytype);
+ $activityxpath = "//li[contains(concat(' ', @class, ' '), ' modtype_" . strtolower($activitytype) . " ')]";
+ $activityxpath .= "[descendant::*[contains(text(), '" . $activityname . "')]]";
$xpathtocheck = "//img[contains(@alt, '$imgalttext')]";
$this->execute("behat_general::should_exist_in_the",
- array($xpathtocheck, "xpath_element", $csselementforactivitytype, "css_element")
+ array($xpathtocheck, "xpath_element", $activityxpath, "xpath_element")
);
-
}
}
$mform->addElement('select', 'calendartype', get_string('forcecalendartype', 'calendar'), $calendars);
}
- $options = range(0, 10);
- $mform->addElement('select', 'newsitems', get_string('newsitemsnumber'), $options);
- $mform->addHelpButton('newsitems', 'newsitemsnumber');
- $mform->setDefault('newsitems', $courseconfig->newsitems);
-
$mform->addElement('selectyesno', 'showgrades', get_string('showgrades'));
$mform->addHelpButton('showgrades', 'showgrades');
$mform->setDefault('showgrades', $courseconfig->showgrades);
$mform->insertElementBefore($mform->removeElement($elements[$i]->getName(), false),
'addcourseformatoptionshere');
}
+
+ if ($courseformat->supports_news()) {
+ // Show the news items select field if the course format supports news.
+ $options = range(0, 10);
+ $newsitems = $mform->createElement('select', 'newsitems', get_string('newsitemsnumber'), $options);
+ $mform->insertElementBefore($newsitems, 'showgrades');
+ $courseconfig = get_config('moodlecourse');
+ $mform->setDefault('newsitems', $courseconfig->newsitems);
+ $mform->addHelpButton('newsitems', 'newsitemsnumber');
+ } else {
+ // Otherwise, create a hidden newsitems element and set its value to 0.
+ $newsitems = $mform->addElement('hidden', 'newsitems', 0);
+ $mform->setType('newsitems', PARAM_INT);
+ $newsitems->setValue(0);
+ }
}
}
return $startdate + $courseduration;
}
+ /**
+ * Indicates whether the course format supports the creation of the Announcements forum.
+ *
+ * For course format plugin developers, please override this to return true if you want the Announcements forum
+ * to be created upon course creation.
+ *
+ * @return bool
+ */
+ public function supports_news() {
+ // For backwards compatibility, check if default blocks include the news_items block.
+ $defaultblocks = $this->get_default_blocks();
+ foreach ($defaultblocks as $blocks) {
+ if (in_array('news_items', $blocks)) {
+ return true;
+ }
+ }
+ // Return false by default.
+ return false;
+ }
+
/**
* Get the start date value from the course settings page form.
*
}
return parent::inplace_editable_render_section_name($section, $linkifneeded, $editable, $edithint, $editlabel);
}
+
+ /**
+ * Indicates whether the course format supports the creation of a news forum.
+ *
+ * @return bool
+ */
+ public function supports_news() {
+ return true;
+ }
}
/**
* Course formats can overwrite get_default_course_enddate function to set the default course end date for new courses.
format_base::get_default_course_enddate uses the new "Course duration" site setting to calculate the default course end date
from the default course start date.
+* New method format_base::supports_news() which is used to determine whether an Announcements forum will be automatically created on
+ course creation. For course format plugin developers, please override format_base::supports_news() to return true if you want the
+ Announcements forum to be created upon course creation and remove the block names defined in format_base::get_default_blocks().
=== 3.1 ===
* Course format may use the inplace_editable template to allow quick editing of section names, see
$dates = $this->get_section_dates(intval($numsections), $startdate);
return $dates->end;
}
+
+ /**
+ * Indicates whether the course format supports the creation of a news forum.
+ *
+ * @return bool
+ */
+ public function supports_news() {
+ return true;
+ }
}
/**
}
if (!empty($fileareas) and (empty($filter) or in_array('fileareas', $filter))) {
$fs = get_file_storage();
- $files = $fs->get_area_files($context->id, $component, $fileareas, false, "filearea, timemodified DESC", true, $from);
+ $files = $fs->get_area_files($context->id, $component, $fileareas, false, "filearea, timemodified DESC", false, $from);
foreach ($fileareas as $filearea) {
$updates->{$filearea . 'files'} = (object) array('updated' => false);
}
// Check comments.
if (plugin_supports('mod', $cm->modname, FEATURE_COMMENT) and (empty($filter) or in_array('comments', $filter))) {
$updates->comments = (object) array('updated' => false);
+ require_once($CFG->dirroot . '/comment/lib.php');
require_once($CFG->dirroot . '/comment/locallib.php');
$manager = new comment_manager();
$comments = $manager->get_component_comments_since($course, $context, $component, $from, $cm);
if ($coursecat->get_children_count()) {
$classes = array(
'collapseexpand',
- 'collapse-all',
);
- if ($chelper->get_subcat_depth() == 1) {
- $classes[] = 'disabled';
- }
+
// Only show the collapse/expand if there are children to expand.
$content .= html_writer::start_tag('div', array('class' => 'collapsible-actions'));
- $content .= html_writer::link('#', get_string('collapseall'),
+ $content .= html_writer::link('#', get_string('expandall'),
array('class' => implode(' ', $classes)));
$content .= html_writer::end_tag('div');
$this->page->requires->strings_for_js(array('collapseall', 'expandall'), 'moodle');
$this->assertFalse($modinfoteacher->get_cm($assign1->cmid)->available);
$this->assertTrue($modinfoteacher->get_cm($assign1->cmid)->uservisible);
}
+
+ /**
+ * Test for supports_news() with a course format plugin that doesn't define 'news_items' in default blocks.
+ */
+ public function test_supports_news() {
+ $this->resetAfterTest();
+ $format = course_get_format((object)['format' => 'testformat']);
+ $this->assertFalse($format->supports_news());
+ }
+
+ /**
+ * Test for supports_news() for old course format plugins that defines 'news_items' in default blocks.
+ */
+ public function test_supports_news_legacy() {
+ $this->resetAfterTest();
+ $format = course_get_format((object)['format' => 'testlegacy']);
+ $this->assertTrue($format->supports_news());
+ }
+}
+
+/**
+ * Class format_testformat.
+ *
+ * A test class that simulates a course format that doesn't define 'news_items' in default blocks.
+ *
+ * @copyright 2016 Jun Pataleta <jun@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class format_testformat extends format_base {
+ /**
+ * Returns the list of blocks to be automatically added for the newly created course.
+ *
+ * @return array
+ */
+ public function get_default_blocks() {
+ return [
+ BLOCK_POS_RIGHT => [],
+ BLOCK_POS_LEFT => []
+ ];
+ }
+}
+
+/**
+ * Class format_testlegacy.
+ *
+ * A test class that simulates old course formats that define 'news_items' in default blocks.
+ *
+ * @copyright 2016 Jun Pataleta <jun@moodle.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class format_testlegacy extends format_base {
+ /**
+ * Returns the list of blocks to be automatically added for the newly created course.
+ *
+ * @return array
+ */
+ public function get_default_blocks() {
+ return [
+ BLOCK_POS_RIGHT => ['news_items'],
+ BLOCK_POS_LEFT => []
+ ];
+ }
}
HASCHILDREN: 'with_children'
},
SELECTORS = {
+ WITHCHILDRENTREES: '.with_children',
LOADEDTREES: '.with_children.loaded',
CONTENTNODE: '.content',
CATEGORYLISTENLINK: '.category .info .categoryname',
CATEGORYSPINNERLOCATION: '.categoryname',
+ CATEGORYWITHCOLLAPSEDCHILDREN: '.category.with_children.collapsed',
CATEGORYWITHCOLLAPSEDLOADEDCHILDREN: '.category.with_children.loaded.collapsed',
CATEGORYWITHMAXIMISEDLOADEDCHILDREN: '.category.with_children.loaded:not(.collapsed)',
COLLAPSEEXPAND: '.collapseexpand',
Y.one(Y.config.doc).delegate('key', this.collapse_expand_all, 'enter', SELECTORS.COLLAPSEEXPAND, this);
};
+/**
+ * Expand all categories.
+ *
+ * @method expand_category
+ * @private
+ * @param {Node} categorynode The node to expand
+ */
+NS.expand_category = function(categorynode) {
+ // Load the actual dependencies now that we've been called.
+ Y.use('io-base', 'json-parse', 'moodle-core-notification', 'anim-node-plugin', function() {
+ // Overload the expand_category with the _expand_category function to ensure that
+ // this function isn't called in the future, and call it for the first time.
+ NS.expand_category = NS._expand_category;
+ NS.expand_category(categorynode);
+ });
+};
+
+NS._expand_category = function(categorynode) {
+ var categoryid,
+ depth;
+
+ if (!categorynode.hasClass(CSS.HASCHILDREN)) {
+ // Nothing to do here - this category has no children.
+ return;
+ }
+
+ if (categorynode.hasClass(CSS.LOADED)) {
+ // We've already loaded this content so we just need to toggle the view of it.
+ this.run_expansion(categorynode);
+ return;
+ }
+
+ // We use Data attributes to store the category.
+ categoryid = categorynode.getData('categoryid');
+ depth = categorynode.getData('depth');
+ if (typeof categoryid === "undefined" || typeof depth === "undefined") {
+ return;
+ }
+
+ this._toggle_generic_expansion({
+ parentnode: categorynode,
+ childnode: categorynode.one(SELECTORS.CONTENTNODE),
+ spinnerhandle: SELECTORS.CATEGORYSPINNERLOCATION,
+ data: {
+ categoryid: categoryid,
+ depth: depth,
+ showcourses: categorynode.getData('showcourses'),
+ type: TYPE_CATEGORY
+ }
+ });
+};
+
/**
* Toggle the animation of the clicked category node.
*
NS.expand_all = function(ancestor) {
var finalexpansions = [];
- ancestor.all(SELECTORS.CATEGORYWITHCOLLAPSEDLOADEDCHILDREN)
+ ancestor.all(SELECTORS.CATEGORYWITHCOLLAPSEDCHILDREN)
.each(function(c) {
- if (c.ancestor(SELECTORS.CATEGORYWITHCOLLAPSEDLOADEDCHILDREN)) {
+ if (c.ancestor(SELECTORS.CATEGORYWITHCOLLAPSEDCHILDREN)) {
// Expand the hidden children first without animation.
c.removeClass(CSS.SECTIONCOLLAPSED);
- c.all(SELECTORS.LOADEDTREES).removeClass(CSS.SECTIONCOLLAPSED);
+ c.all(SELECTORS.WITHCHILDRENTREES).removeClass(CSS.SECTIONCOLLAPSED);
} else {
finalexpansions.push(c);
}
// Run the final expansion with animation on the visible items.
Y.all(finalexpansions).each(function(c) {
- this.run_expansion(c);
+ this.expand_category(c);
}, this);
};
text-align: center;
}
+.mediaplugin,
+.mediaplugin video {
+ /* Make videos as wide as possible without being wider than their containers */
+ width: 100vw;
+ max-width: 100%;
+ height: auto;
+}
+
.mediaplugin > div {
margin: auto;
}
}
$coursecontext = context_course::instance($COURSE->id);
- if ($cohorts = cohort_get_available_cohorts($coursecontext, COHORT_WITH_ENROLLED_MEMBERS_ONLY)) {
+ if ($cohorts = cohort_get_available_cohorts($coursecontext, COHORT_WITH_ENROLLED_MEMBERS_ONLY, 0, 0)) {
$options = array(0 => get_string('anycohort', 'cohort'));
foreach ($cohorts as $c) {
$options[$c->id] = format_string($c->name, true, context::instance_by_id($c->contextid));
http://site.example.com/admin/cron.php?password=opensesame
</pre>If this is left empty, no password is required.';
$string['configcurlcache'] = 'Time-to-live for cURL cache, in seconds.';
-$string['configcustommenuitems'] = 'You can configure a custom menu here to be shown by themes. Each line consists of some menu text, a link URL (optional), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. You can specify a structure using hyphens, and dividers can be used by adding a line of one or more # characters where desired. For example:
+$string['configcustommenuitems'] = 'You can configure a custom menu here to be shown by themes. Each line consists of some menu text, a link URL (optional), a tooltip title (optional) and a language code or comma-separated list of codes (optional, for displaying the line to users of the specified language only), separated by pipe characters. Lines starting with a hyphen will appear as menu items in the previous top level menu, and dividers can be used by adding a line of one or more # characters where desired. For example:
<pre>
Moodle community|https://moodle.org
-Moodle free support|https://moodle.org/support
+-Moodle Docs|http://docs.moodle.org|Moodle Docs
+-German Moodle Docs|http://docs.moodle.org/de|Documentation in German|de
-###
-Moodle development|https://moodle.org/development
---Moodle Docs|http://docs.moodle.org|Moodle Docs
---German Moodle Docs|http://docs.moodle.org/de|Documentation in German|de
-#####
Moodle.com|http://moodle.com/
</pre>';
$string['configcustomusermenuitems'] = 'You can configure the contents of the user menu (with the exception of the log out link, which is automatically added). Each line is separated by | characters and consists of 1) a string in "langstringname, componentname" form or as plain text, 2) a URL, and 3) an icon either as a pix icon or as a URL. Dividers can be used by adding a line of one or more # characters where desired.';
FORM_FIELD_VALIDATION: "core_form-field-validation"
},
+ /**
+ * Load the legacy YUI module which defines events in M.core.event and return it.
+ *
+ * @method getLegacyEvents
+ * @return {Promise}
+ */
+ getLegacyEvents: function() {
+ var result = $.Deferred();
+ Y.use('event', 'moodle-core-event', function() {
+ result.resolve(window.M.core.event);
+ });
+ return result.promise();
+ },
+
/**
* Trigger an event using both JQuery and YUI
*
nodes = $(nodes);
Y.use('event', 'moodle-core-event', function(Y) {
// Trigger it the JQuery way.
- $(document).trigger(M.core.event.FILTER_CONTENT_UPDATED, nodes);
+ $(document).trigger(M.core.event.FILTER_CONTENT_UPDATED, [nodes]);
// Create a YUI NodeList from our JQuery Object.
var yuiNodes = new Y.NodeList(nodes.get());
// Enable web cron.
set_config('cronclionly', 0);
+ // Set editor autosave to high value, so as to avoid unwanted ajax.
+ set_config('autosavefrequency', '604800', 'editor_atto');
+
// Keeps the current version of database and dataroot.
self::store_versions_hash();
}
$this->field->setValue($value);
+
+ // Ensure all pending JS is finished.
+ if ($this->running_javascript()) {
+ $this->session->wait(behat_base::TIMEOUT * 1000, behat_base::PAGE_READY_JS);
+ }
}
}
return true;
}
+ // No need to report the before_scenario warning generated to clear last error.
+ // As error_clear_last is only available in php 7.0+, we trigger E_USER_WARNING
+ // to clear any last error which was generated during reset in before_scenario.
+ if (($errno === E_USER_WARNING) && $errstr == 'before_scenario') {
+ return;
+ }
+
// This error handler receives E_ALL | E_STRICT, running the behat test site the debug level is
// set to DEVELOPER and will always include E_NOTICE,E_USER_NOTICE... as part of E_ALL, if the current
// error_reporting() value does not include one of those levels is because it has been forced through
if ($error = error_get_last()) {
// Ignore E_WARNING, as they might come via ( @ )suppression and might lead to false failure.
if (isset($error['type']) && !($error['type'] & E_WARNING)) {
+
+ // No need to report the before_scenario warning generated to clear last error.
+ // As error_clear_last is only available in php 7.0+, we trigger E_USER_WARNING
+ // to clear any last error which was generated during reset in before_scenario.
+ if (($error['type'] & E_USER_WARNING) && $error['message'] == 'before_scenario') {
+ return;
+ }
+
$errors = behat_get_shutdown_process_errors();
$errors[] = $error;
debugging('message_is_user_blocked() is deprecated and is no longer used, please use
\core_message\api::is_user_blocked() instead.', DEBUG_DEVELOPER);
- return \core_message\api::is_user_blocked($recipient, $sender);
+ $senderid = null;
+ if ($sender !== null && isset($sender->id)) {
+ $senderid = $sender->id;
+ }
+ return \core_message\api::is_user_blocked($recipient->id, $senderid);
}
/**
} else {
$this->rootnodes['courses']->isexpandable = true;
}
-
- // Load the users enrolled courses if they are viewing the My Moodle page AND the admin has not
- // set that they wish to keep the My Courses branch collapsed by default.
$this->rootnodes['mycourses']->forceopen = true;
- $this->load_courses_enrolled();
$canviewcourseprofile = true;
paths: {
jquery: '[JSURL]lib/jquery/jquery-3.1.0.min[JSEXT]',
- jqueryui: '[JSURL]lib/jquery/ui-1.11.4/jquery-ui.min[JSEXT]',
+ jqueryui: '[JSURL]lib/jquery/ui-1.12.1/jquery-ui.min[JSEXT]',
jqueryprivate: '[JSURL]lib/requirejs/jquery-private[JSEXT]'
},
*/
protected static $runningsuite = '';
+ /**
+ * Keeps track of php error generated during reset.
+ *
+ * @var int keep track of how many php errors were generated.
+ */
+ public static $phperrorduringresetcounter = 0;
+
/**
* Hook to capture BeforeSuite event so as to give access to moodle codebase.
* This will try and catch any exception and exists if anything fails.
// Reset $SESSION.
\core\session\manager::init_empty_session();
+ // Set custom handler to try reset all data, if failed because of previous ajax.
+ set_error_handler(
+ function($errno, $errstr, $errfile, $errline) {
+ behat_hooks::$phperrorduringresetcounter++;
+ if (behat_hooks::$phperrorduringresetcounter < self::TIMEOUT) {
+ sleep(1);
+ behat_util::reset_all_data();
+ }
+ return true;
+ }, -1 & ~E_NOTICE & ~E_WARNING);
behat_util::reset_all_data();
+ restore_error_handler();
+
+ // Trigger an error which will be ignored by behat_shutdown_function, this is hacky way to clear last error in php < 7.0.
+ if (self::$phperrorduringresetcounter > 0) {
+ if (function_exists('error_clear_last')) {
+ error_clear_last();
+ } else {
+ trigger_error('before_scenario', E_USER_WARNING);
+ }
+ }
+
+ // Reset the counter here, as this won't be required.
+ self::$phperrorduringresetcounter = 0;
// Assign valid data to admin user (some generator-related code needs a valid user).
$user = $DB->get_record('user', array('username' => 'admin'));
$this->resize_window('medium');
}
+ /**
+ * Executed after scenario to go to a page where no JS is executed.
+ * This will ensure there are no unwanted ajax calls from browser and
+ * site can be reset safely.
+ *
+ * @param AfterScenarioScope $scope scope passed by event fired after scenario.
+ * @AfterScenario
+ */
+ public function after_scenario(AfterScenarioScope $scope) {
+ try {
+ $this->wait_for_pending_js();
+ $this->getSession()->visit($this->locate_path('/README.txt'));
+ $this->getSession()->reset();
+ } catch (DriverException $e) {
+ // Try restart session, if DriverException caught.
+ try {
+ $this->getSession()->restart();
+ } catch (DriverException $e) {
+ // Do nothing, as this will be caught while starting session in before_scenario.
+ }
+ }
+ }
+
/**
* Wait for JS to complete before beginning interacting with the DOM.
*
* @return \stdClass
*/
public static function get_profile($userid, $otheruserid) {
- global $CFG, $DB;
+ global $CFG, $DB, $PAGE;
require_once($CFG->dirroot . '/user/lib.php');
- if ($user = \core_user::get_user($otheruserid)) {
- // Create the data we are going to pass to the renderable.
- $userfields = user_get_user_details($user, null, array('city', 'country', 'email',
- 'profileimageurl', 'profileimageurlsmall', 'lastaccess'));
- if ($userfields) {
- $data = new \stdClass();
- $data->userid = $userfields['id'];
- $data->fullname = $userfields['fullname'];
- $data->city = isset($userfields['city']) ? $userfields['city'] : '';
- $data->country = isset($userfields['country']) ? $userfields['country'] : '';
- $data->email = isset($userfields['email']) ? $userfields['email'] : '';
- $data->profileimageurl = isset($userfields['profileimageurl']) ? $userfields['profileimageurl'] : '';
- if (isset($userfields['profileimageurlsmall'])) {
- $data->profileimageurlsmall = $userfields['profileimageurlsmall'];
- } else {
- $data->profileimageurlsmall = '';
- }
- if (isset($userfields['lastaccess'])) {
- $data->isonline = helper::is_online($userfields['lastaccess']);
- } else {
- $data->isonline = false;
- }
- } else {
- // Technically the access checks in user_get_user_details are correct,
- // but messaging has never obeyed them. In order to keep messaging working
- // we at least need to return a minimal user record.
- $data = new \stdClass();
- $data->userid = $otheruserid;
- $data->fullname = fullname($user);
- $data->city = '';
- $data->country = '';
- $data->email = '';
- $data->profileimageurl = '';
- $data->profileimageurlsmall = '';
- $data->isonline = false;
+ $user = \core_user::get_user($otheruserid, '*', MUST_EXIST);
+
+ // Create the data we are going to pass to the renderable.
+ $data = new \stdClass();
+ $data->userid = $otheruserid;
+ $data->fullname = fullname($user);
+ $data->city = '';
+ $data->country = '';
+ $data->email = '';
+ $data->isonline = false;
+ // Get the user picture data - messaging has always shown these to the user.
+ $userpicture = new \user_picture($user);
+ $userpicture->size = 1; // Size f1.
+ $data->profileimageurl = $userpicture->get_url($PAGE)->out(false);
+ $userpicture->size = 0; // Size f2.
+ $data->profileimageurlsmall = $userpicture->get_url($PAGE)->out(false);
+
+ $userfields = user_get_user_details($user, null, array('city', 'country', 'email', 'lastaccess'));
+ if ($userfields) {
+ if (isset($userfields['city'])) {
+ $data->city = $userfields['city'];
}
- // Check if the contact has been blocked.
- $contact = $DB->get_record('message_contacts', array('userid' => $userid, 'contactid' => $otheruserid));
- if ($contact) {
- $data->isblocked = (bool) $contact->blocked;
- $data->iscontact = true;
- } else {
- $data->isblocked = false;
- $data->iscontact = false;
+ if (isset($userfields['country'])) {
+ $data->country = $userfields['country'];
+ }
+ if (isset($userfields['email'])) {
+ $data->email = $userfields['email'];
}
+ if (isset($userfields['lastaccess'])) {
+ $data->isonline = helper::is_online($userfields['lastaccess']);
+ }
+ }
- return $data;
+ // Check if the contact has been blocked.
+ $contact = $DB->get_record('message_contacts', array('userid' => $userid, 'contactid' => $otheruserid));
+ if ($contact) {
+ $data->isblocked = (bool) $contact->blocked;
+ $data->iscontact = true;
+ } else {
+ $data->isblocked = false;
+ $data->iscontact = false;
}
+
+ return $data;
}
/**
return false;
}
+ $senderid = null;
+ if ($sender !== null && isset($sender->id)) {
+ $senderid = $sender->id;
+ }
// The recipient has specifically blocked this sender.
- if (self::is_user_blocked($recipient, $sender)) {
+ if (self::is_user_blocked($recipient->id, $senderid)) {
return false;
}
* Note: This function will always return false if the sender has the
* readallmessages capability at the system context level.
*
- * @param object $recipient User object.
- * @param object $sender User object.
+ * @param int $recipientid User ID of the recipient.
+ * @param int $senderid User ID of the sender.
* @return bool true if $sender is blocked, false otherwise.
*/
- public static function is_user_blocked($recipient, $sender = null) {
+ public static function is_user_blocked($recipientid, $senderid = null) {
global $USER, $DB;
- if (is_null($sender)) {
+ if (is_null($senderid)) {
// The message is from the logged in user, unless otherwise specified.
- $sender = $USER;
+ $senderid = $USER->id;
}
$systemcontext = \context_system::instance();
- if (has_capability('moodle/site:readallmessages', $systemcontext, $sender)) {
+ if (has_capability('moodle/site:readallmessages', $systemcontext, $senderid)) {
return false;
}
- if ($contact = $DB->get_record('message_contacts', array('userid' => $recipient->id, 'contactid' => $sender->id))) {
- if ($contact->blocked) {
- return true;
- }
+ if ($DB->get_field('message_contacts', 'blocked', ['userid' => $recipientid, 'contactid' => $senderid])) {
+ return true;
}
return false;
defined('MOODLE_INTERNAL') || die();
+use core_message\api;
use renderable;
use templatable;
$data->messages[] = $message->export_for_template($output);
}
+ $data->isblocked = api::is_user_blocked($this->currentuserid, $this->otheruserid);
+
return $data;
}
}
'isonline' => new external_value(PARAM_BOOL, 'The user\'s online status'),
'messages' => new external_multiple_structure(
self::get_messagearea_message_structure()
- )
+ ),
+ 'isblocked' => new external_value(PARAM_BOOL, 'Is this user blocked by the current user?', VALUE_DEFAULT, false),
)
);
}
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
+{{!
+ @template core_message/message_area_messages_area
+
+ Messages area template.
+
+ Classes required for JS:
+ * none
+
+ Data attributes required for JS:
+ * none
+
+ Context variables required for this template:
+ * isonline - boolean
+ * isblocked - boolean
+ * otheruserid - int
+ * otheruserfullname - string
+ * messages - array of messages
+
+ Example context (json):
+ {
+ "isonline": true,
+ "isblocked": true,
+ "otheruserid": 1,
+ "otheruserfullname": "Sam Student",
+ "messages": [
+ {
+ "text": "Hello there!"
+ }
+ ]
+ }
+}}
{{#otheruserid}}
<div class="messages-header">
<div class="view-toggle btn-container">
<div class="name-container">
<div class="name">
<button class="btn btn-link" data-action="view-contact-profile" data-userid="{{otheruserid}}">{{otheruserfullname}}</button>
+ {{#isblocked}}
+ <span data-region="contact-icon-blocked">
+ {{#pix}} t/block, core, {{#str}} contactblocked, message {{/str}} {{/pix}}
+ </span>
+ {{/isblocked}}
</div>
<div class="status {{#isonline}}online{{/isonline}}">
<span class="offline-text">{{#str}} offline, message {{/str}}</span>
$this->setUser($user1);
// User shouldn't be blocked.
- $this->assertFalse(\core_message\api::is_user_blocked($user1, $user2));
+ $this->assertFalse(\core_message\api::is_user_blocked($user1->id, $user2->id));
// Block the user.
message_block_contact($user2->id);
// User should be blocked.
- $this->assertTrue(\core_message\api::is_user_blocked($user1, $user2));
+ $this->assertTrue(\core_message\api::is_user_blocked($user1->id, $user2->id));
+
+ // Unblock the user.
+ message_unblock_contact($user2->id);
+ $this->assertFalse(\core_message\api::is_user_blocked($user1->id, $user2->id));
}
/**
$this->setAdminUser();
// As the admin you should still be able to send messages to the user.
- $this->assertFalse(\core_message\api::is_user_blocked($user1));
+ $this->assertFalse(\core_message\api::is_user_blocked($user1->id));
}
/*
if ($this->can_view_submission($user->id)) {
- if (has_capability('mod/assign:submit', $this->get_context(), $user)) {
+ if (has_capability('mod/assign:submit', $this->get_context(), $user, false)) {
$submissionstatus = $this->get_assign_submission_status_renderable($user, $showlinks);
$o .= $this->get_renderer()->render($submissionstatus);
}
display: table-row;
}
-.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem .fitemtitle,
-.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem .felement {
- display: table-cell;
- float: none;
- border-top: 1px solid #ddd;
- padding: 8px 0;
-}
-
.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem:last-of-type .fitemtitle,
.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem:last-of-type .felement {
border-bottom: 1px solid #ddd;
// If chart data is not visible then expand.
$node = $this->get_selected_node("xpath_element", $charttabledataxpath);
- if ($node && !$node->isVisible()) {
- $this->execute('behat_general::i_click_on_in_the', array(
- get_string('showchartdata'),
- 'link',
- $feedbackxpath,
- 'xpath_element'
- ));
+ if ($node) {
+ if (!$node->isVisible()) {
+ // Focus on node, before checking if it's visible.
+ $node->focus();
+ $this->execute('behat_general::i_click_on_in_the', array(
+ get_string('showchartdata'),
+ 'link',
+ $feedbackxpath,
+ 'xpath_element'
+ ));
+ }
}
}
global $CFG;
$course = $event->get_record_snapshot('course', $event->objectid);
-
- if (!empty($course->newsitems)) {
+ $format = course_get_format($course);
+ if ($format->supports_news() && !empty($course->newsitems)) {
require_once($CFG->dirroot . '/mod/forum/lib.php');
// Auto create the announcements forum.
forum_get_course_forum($event->objectid, 'news');
global $CFG;
$course = $event->get_record_snapshot('course', $event->objectid);
-
- if (!empty($course->newsitems)) {
+ $format = course_get_format($course);
+ if ($format->supports_news() && !empty($course->newsitems)) {
require_once($CFG->dirroot . '/mod/forum/lib.php');
// Auto create the announcements forum.
forum_get_course_forum($event->objectid, 'news');
And I set the following fields to these values:
| Password protected lesson | Yes |
| id_password | moodle_rules |
+ And I wait until the page is ready
And I press "Save and display"
And I navigate to "User overrides" node in "Lesson administration"
And I press "Add user override"
$select = 'id ' . $questionsql . ' AND (timemodified > :time1 OR timecreated > :time2)';
$params['time1'] = $from;
$params['time2'] = $from;
- $questions = $DB->count_records_select('question', $select, $params) > 0;
+ $questions = $DB->get_records_select('question', $select, $params, '', 'id');
if (!empty($questions)) {
$updates->questions->updated = true;
$updates->questions->itemids = array_keys($questions);
And I should see "Play of the game"
And I switch to the main frame
And I follow "Exit activity"
+ And I wait until the page is ready
Then I should see "Basic Multi-sco SCORM package"
And I log out
And I log in as "teacher1"
And I should see "Play of the game"
And I switch to the main frame
And I follow "Exit activity"
+ And I wait until the page is ready
Then I should see "ADV Multi-sco SCORM package"
And I log out
And I log in as "teacher1"
$action .= "§ion=".urlencode($section);
}
- echo $OUTPUT->container_start('mdl-align');
+ echo $OUTPUT->container_start('container');
echo '<form method="post" action="'.$action.'">';
- echo $OUTPUT->container(print_textarea(true, 20, 100, 0, 0, "newcontent", $content, 0, true, '', 'form-textarea-advanced'), 'wiki_editor');
+ $textarea = print_textarea(true, 20, 100, 0, 0, "newcontent", $content, 0, true, '', 'form-textarea-advanced');
+ echo $OUTPUT->container($textarea, 'wiki_editor');
wiki_print_edit_form_default_fields('html', $pageid, $version, $upload, $deleteuploads);
echo '</form>';
echo $OUTPUT->container_end();
$PAGE->requires->js('/mod/wiki/editors/wiki/buttons.js');
- echo $OUTPUT->container_start('mdl-align');
+ echo $OUTPUT->container_start();
foreach ($wiki_editor as $button) {
echo "<a href=\"javascript:insertTags";
echo "('" . $button[2] . "','" . $button[3] . "','" . $button[4] . "');\">";
}
echo $OUTPUT->container_end();
- echo $OUTPUT->container_start('mdl-align');
+ echo $OUTPUT->container_start();
echo '<form method="post" id="mform1" action="' . $action . '">';
echo $OUTPUT->container(print_textarea(false, 20, 60, 0, 0, "newcontent", $content, 0, true), false, 'wiki_editor');
echo $OUTPUT->container_start();
$this->files = $attributes['files'];
unset($attributes['files']);
}
-
-
parent::__construct($elementName, $elementLabel, $attributes);
$this->_type = 'wikieditor';
}
$html .= "</a>";
}
$html .= "<label class='accesshide' for='addtags'>" . get_string('insertimage', 'wiki') . "</label>";
- $html .= "<select id='addtags' onchange=\"insertTags('{$imagetag[0]}', '{$imagetag[1]}', this.value)\">";
+ $html .= "<select id='addtags' class='custom-select m-x-1' " .
+ "onchange=\"insertTags('{$imagetag[0]}', '{$imagetag[1]}', this.value)\">";
$html .= "<option value='" . s(get_string('wikiimage', 'wiki')) . "'>" . get_string('insertimage', 'wiki') . '</option>';
foreach ($this->files as $filename) {
$html .= "<option value='".s($filename)."'>";
public function export_for_template(renderer_base $output) {
$context = $this->export_for_template_base($output);
+
+ // We do want the form-control class on the output from toHTML - but we dont' want it when calling export_for_template.
+ // This is because in this type of form element the export_for_template calls toHTML to get the html for the context.
+ // If we did both we would be duplicating the form-control which messes up the styles.
+ $saved = $this->getAttribute('class');
+ $this->updateAttributes(['class' => $saved . ' form-control']);
+
$context['html'] = $this->toHtml();
+ $this->updateAttributes(['class' => $saved]);
return $context;
}
echo "<fieldset class=\"wiki-upload-section clearfix\"><legend class=\"ftoggler\">" . get_string("uploadtitle", 'wiki') . "</legend>";
- echo $OUTPUT->container_start('mdl-align wiki-form-center aaaaa');
+ echo $OUTPUT->container_start('container');
print $filemanager->toHtml();
echo $OUTPUT->container_end();
$cm = $PAGE->cm;
$context = context_module::instance($cm->id);
- echo $OUTPUT->container_start('mdl-align wiki-form-center wiki-upload-table');
+ echo $OUTPUT->container_start('container wiki-upload-table');
wiki_print_upload_table($context, 'wiki_upload', $pageid, $deleteuploads);
echo $OUTPUT->container_end();
$table = new html_table();
$table->head = array('', get_string('version'), get_string('user'), get_string('modified'), '');
$table->data = $contents;
- $table->attributes['class'] = 'mdl-align';
echo html_writer::table($table);
$table->head = array(get_string('diff', 'wiki') . $icon, get_string('version'), get_string('user'), get_string('modified'), '');
$table->data = $contents;
- $table->attributes['class'] = 'generaltable mdl-align';
+ $table->attributes['class'] = 'table generaltable';
$table->rowclasses = $rowclass;
// Print the form.
echo html_writer::start_tag('form', array('action'=>new moodle_url('/mod/wiki/diff.php'), 'method'=>'get', 'id'=>'diff'));
echo html_writer::tag('div', html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'pageid', 'value'=>$pageid)));
echo html_writer::table($table);
- echo html_writer::start_tag('div', array('class'=>'mdl-align'));
- echo html_writer::empty_tag('input', array('type'=>'submit', 'class'=>'wiki_form-button', 'value'=>get_string('comparesel', 'wiki')));
+ echo html_writer::start_tag('div');
+ echo html_writer::empty_tag('input', array('type'=>'submit', 'class'=>'wiki_form-button btn btn-secondary', 'value'=>get_string('comparesel', 'wiki')));
echo html_writer::end_tag('div');
echo html_writer::end_tag('form');
}
//print_paging_bar($vcount, $paging, $rowsperpage,$CFG->wwwroot.'/mod/wiki/history.php?pageid='.$pageid.'&','paging');
} else {
$link = new moodle_url('/mod/wiki/history.php', array('pageid' => $pageid));
- $OUTPUT->container(html_writer::link($link->out(false), get_string('viewperpage', 'wiki', $this->rowsperpage)), 'mdl-align');
+ $OUTPUT->container(html_writer::link($link->out(false), get_string('viewperpage', 'wiki', $this->rowsperpage)));
}
if ($vcount > $this->rowsperpage && !$this->allversion) {
$link = new moodle_url('/mod/wiki/history.php', array('pageid' => $pageid, 'allversion' => 1));
- $OUTPUT->container(html_writer::link($link->out(false), get_string('viewallhistory', 'wiki')), 'mdl-align');
+ $OUTPUT->container(html_writer::link($link->out(false), get_string('viewallhistory', 'wiki')));
}
}
$table = new html_table();
$table->head = array(get_string('contributions', 'wiki') . $OUTPUT->help_icon('contributions', 'wiki'));
- $table->attributes['class'] = 'wiki_editor generalbox';
+ $table->attributes['class'] = 'generalbox table';
$table->data = array();
$table->rowclasses = array();
$fromlinks = wiki_get_linked_from_pages($page->id);
$table = new html_table();
- $table->attributes['class'] = 'wiki_navigation_from';
+ $table->attributes['class'] = 'wiki_navigation_from table';
$table->head = array(get_string('navigationfrom', 'wiki') . $OUTPUT->help_icon('navigationfrom', 'wiki') . ':');
$table->data = array();
$table->rowclasses = array();
$lpage = wiki_get_page($link->frompageid);
$link = new moodle_url('/mod/wiki/view.php', array('pageid' => $lpage->id));
$table->data[] = array(html_writer::link($link->out(false), format_string($lpage->title)));
- $table->rowclasses[] = 'mdl-align';
}
- $table_left = html_writer::table($table);
+ $table_left = $OUTPUT->container(html_writer::table($table), 'col-md-6 span6');
$table = new html_table();
- $table->attributes['class'] = 'wiki_navigation_to';
+ $table->attributes['class'] = 'wiki_navigation_to table';
$table->head = array(get_string('navigationto', 'wiki') . $OUTPUT->help_icon('navigationto', 'wiki') . ':');
$table->data = array();
$table->rowclasses = array();
$viewlink = new moodle_url('/mod/wiki/view.php', array('pageid' => $lpage->id));
$table->data[] = array(html_writer::link($viewlink->out(false), format_string($lpage->title)));
}
- $table->rowclasses[] = 'mdl-align';
}
- $table_right = html_writer::table($table);
- echo $OUTPUT->container($table_left . $table_right, 'wiki_navigation_container');
+ $table_right = $OUTPUT->container(html_writer::table($table), 'col-md-6 span6');
+ echo $OUTPUT->container($table_left . $table_right, 'wiki_navigation_container row');
}
/**
$table = new html_table();
$table->head = array(get_string('pageindex', 'wiki') . $OUTPUT->help_icon('pageindex', 'wiki'));
- $table->attributes['class'] = 'wiki_editor generalbox';
+ $table->attributes['class'] = 'generalbox table';
$table->data[] = array($this->render_navigation_node($tree));
echo html_writer::table($table);
$table = new html_table();
$table->head = array(get_string('pagelist', 'wiki') . $OUTPUT->help_icon('pagelist', 'wiki'));
- $table->attributes['class'] = 'wiki_editor generalbox';
- $table->align = array('center');
+ $table->attributes['class'] = 'generalbox table';
foreach ($stdaux as $key => $elem) {
$table->data[] = array($key);
foreach ($elem as $e) {
$table = new html_table();
$table->head = array(get_string('orphaned', 'wiki') . $OUTPUT->help_icon('orphaned', 'wiki'));
- $table->attributes['class'] = 'wiki_editor generalbox';
+ $table->attributes['class'] = 'generalbox table';
$table->data = array();
$table->rowclasses = array();
$table = new html_table();
$table->head = array(get_string('updatedpages', 'wiki') . $OUTPUT->help_icon('updatedpages', 'wiki'));
- $table->attributes['class'] = 'wiki_editor generalbox';
+ $table->attributes['class'] = 'generalbox table';
$table->data = array();
$table->rowclasses = array();
$restoreurl = new moodle_url('/mod/wiki/restoreversion.php', $optionsyes);
$return = new moodle_url('/mod/wiki/viewversion.php', array('pageid'=>$this->page->id, 'versionid'=>$version->id));
- echo $OUTPUT->container_start('wiki-form-center');
+ echo $OUTPUT->container_start();
echo html_writer::tag('div', get_string('restoreconfirm', 'wiki', $version->version));
echo $OUTPUT->container_start(false, 'wiki_restoreform');
echo '<form class="wiki_restore_yes" action="' . $restoreurl . '" method="post" id="restoreversion">';
$deleteurl = new moodle_url('/mod/wiki/instancecomments.php', $optionsyes);
$return = new moodle_url('/mod/wiki/comments.php', array('pageid'=>$this->page->id));
- echo $OUTPUT->container_start('wiki-form-center');
+ echo $OUTPUT->container_start();
echo html_writer::tag('p', $strdeletecheckfull);
echo $OUTPUT->container_start(false, 'wiki_deletecommentform');
echo '<form class="wiki_deletecomment_yes" action="' . $deleteurl . '" method="post" id="deletecomment">';
$viewlink = new moodle_url('/user/view.php', array('id' => $userinfo->id));
$heading .= ' <strong>' . get_string('user') . ':</strong> ' . html_writer::link($viewlink->out(false), fullname($userinfo));
$heading .= ' → ' . $OUTPUT->user_picture(wiki_get_user_info($pageversion->userid), array('popup' => true)) . '</p>';
- echo $OUTPUT->container($heading, 'wiki_headingtime', 'mdl-align wiki_modifieduser');
+ echo $OUTPUT->container($heading, 'wiki_headingtime', 'wiki_modifieduser');
$options = array('swid' => $this->subwiki->id, 'pretty_print' => true, 'pageid' => $this->page->id);
$pageversion->content = file_rewrite_pluginfile_urls($pageversion->content, 'pluginfile.php', $this->modcontext->id, 'mod_wiki', 'attachments', $this->subwiki->id);
$contents = array();
$table = new html_table();
$table->head = array('', get_string('pagename','wiki'));
- $table->attributes['class'] = 'generaltable mdl-align';
+ $table->attributes['class'] = 'table generaltable';
$swid = $this->subwiki->id;
if ($showorphan) {
if ($orphanedpages = wiki_get_orphaned_pages($swid)) {
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'option', 'value' => $this->view));
echo html_writer::table($table);
- echo html_writer::start_tag('div', array('class' => 'mdl-align'));
+ echo html_writer::start_tag('div');
if (!$showorphan) {
echo html_writer::empty_tag('input', array(
'type' => 'submit',
echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'listall', 'value'=>'1'));
echo html_writer::empty_tag('input', array(
'type' => 'submit',
- 'class' => 'wiki_form-button',
+ 'class' => 'wiki_form-button btn btn-secondary',
'value' => get_string('listall', 'wiki'),
'sesskey' => sesskey()));
}
$table = new html_table();
$table->head = array('', get_string('version'), get_string('user'), get_string('modified'), '');
$table->data = $contents;
- $table->attributes['class'] = 'mdl-align';
echo html_writer::table($table);
} else {
$table = new html_table();
$table->head = array(get_string('deleteversions', 'wiki'), get_string('version'), get_string('user'), get_string('modified'), '');
$table->data = $contents;
- $table->attributes['class'] = 'generaltable mdl-align';
+ $table->attributes['class'] = 'table generaltable';
$table->rowclasses = $rowclass;
///Print the form
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'option', 'value' => $this->view));
echo html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
echo html_writer::table($table);
- echo html_writer::start_tag('div', array('class' => 'mdl-align'));
- echo html_writer::empty_tag('input', array('type' => 'submit', 'class' => 'wiki_form-button', 'value' => get_string('deleteversions', 'wiki')));
+ echo html_writer::start_tag('div');
+ echo html_writer::empty_tag('input', array('type' => 'submit', 'class' => 'wiki_form-button btn btn-secondary', 'value' => get_string('deleteversions', 'wiki')));
echo html_writer::end_tag('div');
echo html_writer::end_tag('form');
}
min-height: 100px;
}
-.wiki_editor {
- width: 50%;
- margin: auto;
- margin-top: 10px;
- margin-bottom: 10px;
-}
-
.wiki_previewbox {
width: 50%;
margin: auto;
margin-left: 0%;
}
-.wiki-form-center {
- text-align: center;
- margin: auto;
- width: 320px;
-}
-
.wiki-upload-table {
margin: 8px auto;
clear: both;
text-align: right;
}
-.wikieditor-toolbar img {
- width: 22px;
- height: 22px;
- vertical-align: middle;
-}
-
.path-mod-wiki .printicon {
background: url([[pix:t/print]]) no-repeat scroll 2px center transparent;
padding-left: 20px;
$this->foldernamecache = cache::make('repository_skydrive', 'foldername');
}
- /**
- * Should HTTP GET be used instead of POST?
- *
- * The Microsoft API does not support POST, so we should use
- * GET instead (with the auth_token passed as a GET param).
- *
- * @return bool true if GET should be used
- */
- protected function use_http_get() {
- return true;
- }
-
/**
* Returns the auth url for OAuth 2.0 request
* @return string the auth url
return 'https://login.live.com/oauth20_token.srf';
}
+ /**
+ * Post request.
+ *
+ * Overridden to convert the data to a string, else curl will set the wrong headers.
+ *
+ * @param string $url The URL.
+ * @param array|string $params The parameters.
+ * @param array $options The options.
+ * @return bool
+ */
+ public function post($url, $params = '', $options = array()) {
+ return parent::post($url, format_postdata_for_curlcall($params), $options);
+ }
+
/**
* Downloads a file to a file from skydrive using authenticated request
*
}
public function get_file($url, $title = '') {
$url = urldecode($url);
- $path = $this->prepare_file($title);
+ $path = $this->prepare_file();
if (!$this->dav->open()) {
return false;
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 2.9
*/
-define(['jquery', './tether'], function(jQuery, Tether) {
+define(['jquery', './tether', 'core/event'], function(jQuery, Tether, Event) {
window.jQuery = jQuery;
window.Tether = Tether;
'theme_boost/tooltip',
'theme_boost/popover'],
function() {
+
+ jQuery('body').popover({
+ selector: '[data-toggle="popover"]',
+ trigger: 'focus'
+ });
+
+ // We need to call popover automatically if nodes are added to the page later.
+ Event.getLegacyEvents().done(function(events) {
+ jQuery(document).on(events.FILTER_CONTENT_UPDATED, function() {
jQuery('body').popover({
selector: '[data-toggle="popover"]',
trigger: 'focus'
});
+ });
+ });
});
+
return {};
});
return $skipped;
}
+ /**
+ * Secure login info.
+ *
+ * @return string
+ */
+ public function secure_login_info() {
+ return $this->login_info(false);
+ }
}
defined('MOODLE_INTERNAL') || die();
+$blockshtml = $OUTPUT->blocks('side-pre');
+$hasblocks = strpos($blockshtml, 'data-block=') !== false;
+$bodyattributes = $OUTPUT->body_attributes();
+
$templatecontext = [
'sitename' => format_string($SITE->shortname, true, array('context' => context_course::instance(SITEID))),
'output' => $OUTPUT,
- 'sidepreblocks' => $OUTPUT->blocks('side-pre'),
+ 'bodyattributes' => $bodyattributes,
+ 'sidepreblocks' => $blockshtml,
+ 'hasblocks' => $hasblocks
];
echo $OUTPUT->render_from_template('theme_boost/secure', $templatecontext);
#adminsettings .form-overridden {
@extend .form-control-feedback;
+ @extend .alert-info;
}
.modal.modal-in-page {
width: 98%;
height: 98%;
}
+.file-picker .fp-def-search {
+ margin-top: 0;
+}
// Repositories on fp-repo-area (File Picker only)
.file-picker .fp-list {
list-style-type: none;
border: 1px solid #e3e3e3;
clear: both;
+ img {
+ max-width: 100%;
+ }
+
.contacts-area {
border-right: 1px solid #e3e3e3;
height: 600px;
float: left;
width: 20rem;
display: inline-block;
- height: 12rem;
+ min-height: 12rem;
}
#page-mod-quiz-mod #id_reviewoptionshdr .btn-link {
float: left;
clear: left;
}
-#page-mod-quiz-mod #id_reviewoptionshdr .form-check-inline {
+#page-mod-quiz-mod #id_reviewoptionshdr .form-check {
width: 90%;
height: 22px;
}
}
}
-/**
- * Assign.
- */
+
+// Assign.
.path-mod-assign [data-region="grade-actions-panel"] [data-region="grade-actions"] .collapse-buttons {
top: auto;
}
overflow: initial;
}
-.path-mod-assign [data-region="grade-panel"] .has-popout {
- background-color: $card-bg;
+// This section removes the responsiveness from the form in the grading panel
+$popout-header-font-size: 1.5 * $font-size-base;
+// This can't be calculated from modal-title-padding because we are mixing px and rem units.
+$popout-header-height: 4rem;
- @include border-radius($card-border-radius);
- border: $card-border-width solid $card-border-color;
+.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) .fcontainer .fitem.popout .felement {
+ height: calc(100% - #{$popout-header-height});
+}
+
+.path-mod-assign [data-region="grade-panel"] {
+ padding-top: $spacer;
+}
+.path-mod-assign [data-region="grade-panel"] .fitem > .col-md-3,
+.path-mod-assign [data-region="grade-panel"] .fitem > .col-md-9 {
+ width: 100%;
+ padding: 0;
+}
+.path-mod-assign [data-region="grade-panel"] fieldset,
+.path-mod-assign [data-region="grade-panel"] .fitem.row {
+ margin: 0;
+}
+
+.path-mod-assign [data-region="grade-panel"] .fitem > .col-md-3 > .pull-xs-right {
+ float: none !important; /* stylelint-disable-line declaration-no-important */
+}
+
+.path-mod-assign [data-region="grade-panel"] .mform .fitem.has-popout .felement {
+ width: 100%;
}
+.path-mod-assign [data-region="grade-panel"] .mform .fitem .felement {
+ width: auto;
+}
+
+// Now styles for the popout sections.
+
.path-mod-assign [data-region="grade-panel"] .popout {
background-color: $modal-content-bg;
}
-.path-mod-assign [data-region="grade-panel"] .col-md-3 {
- width: 100%;
+.path-mod-assign [data-region="grade-panel"] .fitem.has-popout {
+ background-color: $card-bg;
+ @include border-radius($card-border-radius);
+ border: $card-border-width solid $card-border-color;
+ padding: $card-spacer-x;
+ margin-bottom: $spacer;
+}
+.path-mod-assign [data-region="grade-panel"] .has-popout .col-md-3 {
+ border-bottom: $hr-border-width solid $hr-border-color;
+ margin-bottom: $spacer;
}
+
.path-mod-assign [data-region="grade-panel"] .popout > .col-md-3 {
@extend .modal-header;
- font-size: 1.5rem;
-}
-
-.path-mod-assign [data-region="grade-panel"] [data-region="popout-button"] {
- margin-top: 0.5rem;
+ font-size: $popout-header-font-size;
}
.path-mod-assign [data-region="grade-panel"] .popout [data-region="popout-button"] {
margin-top: 0;
}
-.path-mod-assign [data-region="grade-panel"] h3 {
- margin: 10px 0;
- line-height: 40px;
-}
+// Now style the fixed header elements.
.path-mod-assign [data-region="assignment-info"] {
overflow-y: hidden;
height: 85px;
}
+@media (max-width: 767px) {
+ .path-mod-assign [data-region="grading-navigation-panel"] {
+ height: auto;
+ }
+ .path-mod-assign [data-region="user-info"] {
+ margin-top: 1rem;
+ }
+}
+
.path-mod-assign [data-region="grading-navigation"] [data-region="input-field"] input {
width: auto;
display: inline-block;
]
}
}}
-<ol class="breadcrumb" role="navigation">
- {{#get_items}}
- {{#has_action}}
- <li class="breadcrumb-item"><a href="{{{action}}}" {{#get_title}}title="{{get_title}}"{{/get_title}}>{{{text}}}</a></li>
- {{/has_action}}
- {{^has_action}}
- <li class="breadcrumb-item">{{{text}}}</li>
- {{/has_action}}
- {{/get_items}}
-</ol>
+<nav role="navigation">
+ <ol class="breadcrumb">
+ {{#get_items}}
+ {{#has_action}}
+ <li class="breadcrumb-item"><a href="{{{action}}}" {{#get_title}}title="{{get_title}}"{{/get_title}}>{{{text}}}</a></li>
+ {{/has_action}}
+ {{^has_action}}
+ <li class="breadcrumb-item">{{{text}}}</li>
+ {{/has_action}}
+ {{/get_items}}
+ </ol>
+</nav>
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ @template core_form/element-select
+
+ Simple select form element template.
+
+ Context variables required for this template:
+ * id - Element id,
+ * name - Element name,
+ * label - Element label,
+ * multiple - multi select?,
+ * checked - checked?,
+ * error - Is there an error associated with this element?,
+ * size - Element size,
+ * value - Element value,
+ * helpbutton - Helpbutton,
+ * hiddenlabel - Element hidden flag,
+ * frozen - Element frozen flag,
+ * hardfrozen - Element hard fronzen flag,
+ * extraclasses - Extra classes assocaited,
+ * type - Element type,
+ * attributes - Element attributes,
+ * options - [
+ {
+ text - Option text,
+ value - Option value,
+ selected - Selected?,
+ disabled - Disabled?,
+ optionattributes - Option attributes
+ }
+ ]
+
+ Example context (json):
+ {
+ "element": {
+ "id": "id_maildisplay",
+ "name": "maildisplay",
+ "label": null,
+ "multiple": null,
+ "checked": null,
+ "error": null,
+ "size": null,
+ "value": null,
+ "helpbutton": "",
+ "hiddenlabel": false,
+ "frozen": false,
+ "hardfrozen": false,
+ "extraclasses": null,
+ "type": "select",
+ "attributes": "",
+ "options": [
+ {
+ "text": "Hide my email address from everyone",
+ "value": 0,
+ "selected": false,
+ "disabled": false,
+ "optionattributes": ""
+ },
+ {
+ "text": "Allow everyone to see my email address",
+ "value": 1,
+ "selected": true,
+ "disabled": false,
+ "optionattributes": ""
+ },
+ {
+ "text": "Allow only other course members to see my email address",
+ "value": 2,
+ "selected": false,
+ "disabled": false,
+ "optionattributes": ""
+ }
+ ]
+ }
+ }
+}}
{{< core_form/element-template }}
{{$element}}
{{^element.frozen}}
{{/error}}
{{{element.attributes}}} >
{{#element.options}}
- <option value="{{value}}" {{#selected}}selected{{/selected}} {{#disabled}}disabled{{/disabled}} {{{optionattributes}}}>{{text}}</option>
+ <option value="{{value}}" {{#selected}}selected{{/selected}} {{#disabled}}disabled{{/disabled}}
+ {{{optionattributes}}}>{{{text}}}</option>
{{/element.options}}
</select>
{{/element.frozen}}
--- /dev/null
+{{!
+ This file is part of Moodle - http://moodle.org/
+
+ Moodle is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Moodle is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+}}
+{{!
+ Page header.
+}}
+<header role="banner" class="pos-f-t navbar navbar-full navbar-light bg-faded navbar-static-top moodle-has-zindex">
+
+ <div class="container-fluid">
+
+ <span class="navbar-brand {{# output.should_display_navbar_logo }}has-logo{{/ output.should_display_navbar_logo }}
+ {{^ output.should_display_navbar_logo }}
+ hidden-sm-down
+ {{/ output.should_display_navbar_logo }}
+ ">
+
+ {{# output.should_display_navbar_logo }}
+ <span class="logo hidden-xs-down">
+ <img src="{{output.get_compact_logo_url}}" alt="{{sitename}}">
+ </span>
+ {{/ output.should_display_navbar_logo }}
+ <span class="site-name hidden-sm-down">{{{ sitename }}}</span>
+ </span>
+ <div class="pull-xs-right nav-link">
+ {{{ output.secure_login_info }}}
+ </div>
+
+ </div>
+</header>
+
<button aria-expanded="{{#navdraweropen}}true{{/navdraweropen}}{{^navdraweropen}}false{{/navdraweropen}}" aria-controls="nav-drawer" type="button" class="btn pull-xs-left m-r-1 btn-secondary" data-action="toggle-drawer" data-side="left" data-preference="drawer-open-nav">☰<span class="sr-only">{{#str}}expand, core{{/str}}</span></button>
</div>
- <a role="banner" href="{{{ config.wwwroot }}}" class="navbar-brand {{# output.should_display_navbar_logo }}has-logo{{/ output.should_display_navbar_logo }}
+ <a href="{{{ config.wwwroot }}}" class="navbar-brand {{# output.should_display_navbar_logo }}has-logo{{/ output.should_display_navbar_logo }}
{{^ output.should_display_navbar_logo }}
hidden-sm-down
{{/ output.should_display_navbar_logo }}
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
-<body {{{ output.body_attributes }}}>
+<body {{{ bodyattributes }}}>
-{{{ output.standard_top_of_body_html }}}
+<div id="page-wrapper">
-<header class="navbar navbar-full navbar-light bg-faded navbar-static-top moodle-has-zindex">
- <div class="container">
- <div class="clearfix">
- <button class="navbar-toggler pull-xs-right hidden-sm-up" data-toggle="collapse" data-target="#bd-main-mav">☰<span class="sr-only">{{#str}}expand{{/str}}</span></button>
- </div>
+ {{{ output.standard_top_of_body_html }}}
- <a role="banner" href="{{{ config.wwwroot }}}" class="navbar-brand">
- {{# output.should_display_navbar_logo }}
- <div class="logo">
- <img src="{{output.get_compact_logo_url}}" alt={{#quote}}{{sitename}}{{/quote}}>
- </div>
- {{/ output.should_display_navbar_logo }}
- <div class="site-name">{{{ sitename }}}</div>
- </a>
+ {{>theme_boost/header-secure}}
- <div class="collapse navbar-toggleable-xs" id="bd-main-nav">
- <nav class="nav navbar-nav">
- <!-- search_box -->
- {{{ output.search_box }}}
- <!-- custom_menu -->
- {{{ output.custom_menu }}}
- <!-- page_heading_menu -->
- {{{ output.page_heading_menu }}}
- <!-- login info -->
- {{{ output.login_info }}}
- </nav>
- </div>
- </div>
-</header>
+ <div id="page" class="container-fluid">
+ {{! Secured full header }}
-<div id="page" class="container">
- {{{ output.full_header }}}
+ <div id="page-header" class="row">
+ <div class="col-xs-12 p-y-1">
+ <div class="page-context-header">
+ <div class="page-header-headings">
+ {{{ output.page_heading }}}
+ </div>
+ </div>
+ </div>
+ </div>
- <div id="page-content" class="row">
- <div id="region-main-box" class="col-xs-12">
- <div class="row">
- <section id="region-main" class="col-xs-12">
+ <div id="page-content" class="row">
+ <div id="region-main-box" class="col-xs-12">
+ <section id="region-main" {{#hasblocks}}class="has-blocks"{{/hasblocks}}>
+ <div class="card card-block">
+ {{{ output.course_content_header }}}
{{{ output.main_content }}}
+ {{{ output.course_content_footer }}}
+ </div>
+ </section>
+ {{#hasblocks}}
+ <section data-region="blocks-column">
+ {{{ sidepreblocks }}}
</section>
+ {{/hasblocks}}
</div>
</div>
</div>
+</div>
+<footer id="page-footer" class="p-y-1 bg-inverse">
+ <div class="container">
+ <div id="course-footer">{{{ output.course_footer }}}</div>
- {{{ output.standard_end_of_body_html }}}
+ {{{ output.standard_end_of_body_html }}}
+ </div>
+</footer>
-</div>
</body>
</html>
{{#js}}
+++ /dev/null
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/**
- * Basic authentication steps definitions.
- *
- * @package core_auth
- * @category test
- * @copyright 2012 David Monllaó
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
-
-require_once(__DIR__ . '/../../../../lib/behat/behat_base.php');
-require_once(__DIR__ . '/../../../../auth/tests/behat/behat_auth.php');
-
-/**
- * Log in log out steps definitions.
- *
- * @package core_auth
- * @category test
- * @copyright 2012 David Monllaó
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class behat_theme_boost_behat_auth extends behat_auth {
-
- public function i_log_out() {
- // There is no longer any need to worry about whether the navigation
- // bar needs to be expanded; user_menu now lives outside the
- // hamburger.
-
- // However, the user menu *always* needs to be expanded. if running JS.
- if ($this->running_javascript()) {
- $xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' dropdown-toggle ')]";
-
- $this->execute('behat_general::i_click_on', array($xpath, "xpath_element"));
- }
-
- // No need to check for exceptions as it will checked after this step execution.
- $this->execute('behat_general::click_link', get_string('logout'));
- }
-}
}
/*rtl:raw:
.collapsible-actions .collapseexpand {
- background: url([[pix:t/collapsed_rtl]]);
+ background: url([[pix:t/collapsed_rtl]]) right center no-repeat;
}
*/
.collapsible-actions .collapse-all {
.mform fieldset.collapsible legend a.fheader {
padding: 0 5px 0 20px;
margin-left: -20px;
- background: url([[pix:t/expanded]]) 2px center no-repeat;
+ background: url([[pix:t/expanded]]) left center no-repeat;
}
.mform fieldset.collapsed legend a.fheader {
/*rtl:raw:
clear: both;
border-radius: 4px;
+ img {
+ max-width: 100%;
+ }
+
.contacts-area {
border-right: 1px solid #e3e3e3;
height: 600px;
width: auto;
}
+// Assign
+.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem {
+ .fitemtitle,
+ .felement {
+ display: table-cell;
+ float: none;
+ border-top: 1px solid #ddd;
+ padding: 8px 0;
+ }
+}
+
// Feedback module
.path-mod-feedback .mform.feedback_form .fitem .fitemtitle {
display: block;
}
/*rtl:raw:
.collapsible-actions .collapseexpand {
- background: url([[pix:t/collapsed_rtl]]);
+ background: url([[pix:t/collapsed_rtl]]) right center no-repeat;
}
*/
.collapsible-actions .collapse-all {
clear: both;
border-radius: 4px;
}
+.messaging-area-container .messaging-area img {
+ max-width: 100%;
+}
.messaging-area-container .messaging-area .contacts-area {
border-right: 1px solid #e3e3e3;
height: 600px;
.mform fieldset.collapsible legend a.fheader {
padding: 0 5px 0 20px;
margin-left: -20px;
- background: url([[pix:t/expanded]]) 2px center no-repeat;
+ background: url([[pix:t/expanded]]) left center no-repeat;
}
.mform fieldset.collapsed legend a.fheader {
/*rtl:raw:
select {
width: auto;
}
+.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem .fitemtitle,
+.path-mod-assign #page-content [data-region="grade-panel"] .mform:not(.unresponsive) #id_attemptsettings .fitem .felement {
+ display: table-cell;
+ float: none;
+ border-top: 1px solid #ddd;
+ padding: 8px 0;
+}
.path-mod-feedback .mform.feedback_form .fitem .fitemtitle {
display: block;
margin-top: 4px;
defined('MOODLE_INTERNAL') || die();
-$version = 2016111800.00; // YYYYMMDD = weekly release date of this DEV branch.
+$version = 2016112200.00; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
-$release = '3.2rc1 (Build: 20161118)'; // Human-friendly version name
+$release = '3.2rc2 (Build: 20161122)'; // Human-friendly version name
$branch = '32'; // This version's branch.
$maturity = MATURITY_RC; // This version's maturity level.