Merge branch 'MDL-63337-master' of git://github.com/bmbrands/moodle

This commit is contained in:
Jun Pataleta
2018-10-15 21:03:16 +08:00
56 changed files with 1612 additions and 1853 deletions
+1
View File
@@ -0,0 +1 @@
define(["jquery","block_myoverview/view","block_myoverview/view_nav"],function(a,b,c){var d={COURSES_VIEW:'[data-region="courses-view"]',COURSES_VIEW_CONTENT:'[data-region="course-view-content"]'},e=function(e){e=a(e);var f=e.find(d.COURSES_VIEW),g=e.find(d.COURSES_VIEW_CONTENT);c.init(e,f,g),b.init(f,g)};return{init:e}});
-1
View File
@@ -1 +0,0 @@
define(["jquery","core/custom_interaction_events"],function(a,b){var c={ROOT:'[data-region="paging-bar"]',PAGE_ITEM:'[data-region="page-item"]',ACTIVE_PAGE_ITEM:'[data-region="page-item"].active'},d={PAGE_SELECTED:"block_myoverview-paging-bar-page-selected"},e=function(a,b){return a.find(c.PAGE_ITEM+'[data-page-number="'+b+'"]')},f=function(a,b){var c=b.attr("data-page-number");return"first"==c?c=1:"last"==c&&(c=a.attr("data-page-count")),c},g=function(g){g=a(g),b.define(g,[b.events.activate]),g.on(b.events.activate,c.PAGE_ITEM,function(b,h){var i=a(b.target).closest(c.PAGE_ITEM),j=g.find(c.ACTIVE_PAGE_ITEM),k=f(g,i),l=k==f(g,j);l||(g.find(c.PAGE_ITEM).removeClass("active"),e(g,k).addClass("active")),g.trigger(d.PAGE_SELECTED,[{pageNumber:k,isSamePage:l}]),h.originalEvent.preventDefault()})};return{registerEventListeners:g,events:d,rootSelector:c.ROOT}});
-1
View File
@@ -1 +0,0 @@
define(["jquery","core/templates","block_myoverview/paging_bar"],function(a,b,c){var d={ROOT:'[data-region="paging-content"]',PAGE_REGION:'[data-region="paging-content-item"]'},e=function(b,c){this.root=a(b),this.pagingBar=a(c)};return e.rootSelector=d.ROOT,e.prototype.createPage=function(a){return this.loadContent(a).then(function(a,c){b.appendNodeContents(this.root,a,c)}.bind(this)).then(function(){return this.findPage(a)}.bind(this))},e.prototype.findPage=function(a){return this.root.find('[data-page="'+a+'"]')},e.prototype.showPage=function(a){var b=this.findPage(a);this.root.find(d.PAGE_REGION).addClass("hidden"),b.length?b.removeClass("hidden"):this.createPage(a).done(function(a){a.removeClass("hidden")})},e.prototype.registerEventListeners=function(){this.pagingBar.on(c.events.PAGE_SELECTED,function(a,b){b.isSamePage||this.showPage(b.pageNumber)}.bind(this))},e});
+1
View File
@@ -0,0 +1 @@
define(["core/ajax"],function(a){var b=function(b){var c={methodname:"core_course_get_enrolled_courses_by_timeline_classification",args:b},d=a.call([c])[0];return d};return{getEnrolledCoursesByTimeline:b}});
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/notification","block_myoverview/repository","core/paged_content_factory","core/templates"],function(a,b,c,d,e){var f={COURSES_CARDS:"block_myoverview/view-cards",COURSES_LIST:"block_myoverview/view-list",COURSES_SUMMARY:"block_myoverview/view-summary",NOCOURSES:"block_myoverview/no-courses"},g=[12,24],h=[],i=function(a){var b={};return b.display=a.attr("data-display"),b.grouping=a.attr("data-grouping"),b.sort=a.attr("data-sort"),b},j={ignoreControlWhileLoading:!0,controlPlacementBottom:!0},k=function(a,b,d){return c.getEnrolledCoursesByTimeline({offset:d*b,limit:b,classification:a.grouping,sort:a.sort})},l=function(a,b,c){var d="";if(d="cards"==c.display?f.COURSES_CARDS:"list"==c.display?f.COURSES_LIST:f.COURSES_SUMMARY,b.courses.length)return e.render(d,{courses:b.courses});var g=a.attr("data-nocoursesimg");return e.render(f.NOCOURSES,{nocoursesimg:g})},m=function(c,f){c=a(c);var m=i(c),n=d.createWithLimit(g,function(a,d){var e=[];return a.forEach(function(a){var f=a.pageNumber-1,g=k(m,a.limit,f).then(function(b){return b.courses.length<a.limit&&d.allItemsLoaded(a.pageNumber),h=b,l(c,b,m)})["catch"](b.exception);e.push(g)}),e},j);n.then(function(a,b){return e.replaceNodeContents(f,a,b)})["catch"](b.exception)},n=function(a,c){var d=i(a);l(a,h,d).then(function(a,b){return e.replaceNodeContents(c,a,b)})["catch"](b.exception)};return{init:m,reset:n}});
+1
View File
@@ -0,0 +1 @@
define(["jquery","core/custom_interaction_events","block_myoverview/view"],function(a,b,c){var d={FILTERS:'[data-region="filter"]',FILTER_OPTION:"[data-filter]",DISPLAY_OPTION:"[data-display-option]"},e=function(e,f,g){var h=e.find(d.FILTERS);b.define(h,[b.events.activate]),h.on(b.events.activate,d.FILTER_OPTION,function(b,d){var e=a(b.target);if(!e.hasClass("active")){var h="data-"+e.attr("data-filter");f.attr(h,e.attr("data-value")),c.init(f,g),d.originalEvent.preventDefault()}}),b.define(h,[b.events.activate]),h.on(b.events.activate,d.DISPLAY_OPTION,function(b,d){var e=a(b.target);e.hasClass("active")||(f.attr("data-display",e.attr("data-value")),c.reset(f,g),d.originalEvent.preventDefault())})},f=function(b,c,d){b=a(b),e(b,c,d)};return{init:f}});
+58
View File
@@ -0,0 +1,58 @@
// 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/>.
/**
* Javascript to initialise the myoverview block.
*
* @package block_myoverview
* @copyright 2018 Bas Brands <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'block_myoverview/view',
'block_myoverview/view_nav'
],
function(
$,
View,
ViewNav
) {
var SELECTORS = {
COURSES_VIEW: '[data-region="courses-view"]',
COURSES_VIEW_CONTENT: '[data-region="course-view-content"]'
};
/**
* Initialise all of the modules for the overview block.
*
* @param {object} root The root element for the overview block.
*/
var init = function(root) {
root = $(root);
var coursesViewRoot = root.find(SELECTORS.COURSES_VIEW);
var coursesViewContent = root.find(SELECTORS.COURSES_VIEW_CONTENT);
// Initialise the course navigation elements.
ViewNav.init(root, coursesViewRoot, coursesViewContent);
// Initialise the courses view modules.
View.init(coursesViewRoot, coursesViewContent);
};
return {
init: init
};
});
-102
View File
@@ -1,102 +0,0 @@
// 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/>.
/**
* Javascript to load and render the paging bar.
*
* @module block_myoverview/paging_bar
* @package block_myoverview
* @copyright 2016 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/custom_interaction_events'],
function($, CustomEvents) {
var SELECTORS = {
ROOT: '[data-region="paging-bar"]',
PAGE_ITEM: '[data-region="page-item"]',
ACTIVE_PAGE_ITEM: '[data-region="page-item"].active'
};
var EVENTS = {
PAGE_SELECTED: 'block_myoverview-paging-bar-page-selected',
};
/**
* Get the page element by number.
*
* @param {object} root The root element.
* @param {Number} pageNumber The page number.
* @returns {*}
*/
var getPageByNumber = function(root, pageNumber) {
return root.find(SELECTORS.PAGE_ITEM + '[data-page-number="' + pageNumber + '"]');
};
/**
* Get the page number.
*
* @param {object} root The root element.
* @param {object} page The page.
* @returns {*} the page number
*/
var getPageNumber = function(root, page) {
var pageNumber = page.attr('data-page-number');
if (pageNumber == 'first') {
pageNumber = 1;
} else if (pageNumber == 'last') {
pageNumber = root.attr('data-page-count');
}
return pageNumber;
};
/**
* Register event listeners for the module.
* @param {object} root The root element.
*/
var registerEventListeners = function(root) {
root = $(root);
CustomEvents.define(root, [
CustomEvents.events.activate
]);
root.on(CustomEvents.events.activate, SELECTORS.PAGE_ITEM, function(e, data) {
var page = $(e.target).closest(SELECTORS.PAGE_ITEM);
var activePage = root.find(SELECTORS.ACTIVE_PAGE_ITEM);
var pageNumber = getPageNumber(root, page);
var isSamePage = pageNumber == getPageNumber(root, activePage);
if (!isSamePage) {
root.find(SELECTORS.PAGE_ITEM).removeClass('active');
getPageByNumber(root, pageNumber).addClass('active');
}
root.trigger(EVENTS.PAGE_SELECTED, [{
pageNumber: pageNumber,
isSamePage: isSamePage,
}]);
data.originalEvent.preventDefault();
});
};
return {
registerEventListeners: registerEventListeners,
events: EVENTS,
rootSelector: SELECTORS.ROOT,
};
});
-105
View File
@@ -1,105 +0,0 @@
// 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/>.
/**
* Paging content module.
*
* @module block_myoverview/paging_content
* @package block_myoverview
* @copyright 2016 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/templates', 'block_myoverview/paging_bar'],
function($, Templates, PagingBar) {
var SELECTORS = {
ROOT: '[data-region="paging-content"]',
PAGE_REGION: '[data-region="paging-content-item"]'
};
/**
* Constructor of the paging content module.
*
* @param {object} root
* @param {object} pagingBarElement
* @constructor
*/
var PagingContent = function(root, pagingBarElement) {
this.root = $(root);
this.pagingBar = $(pagingBarElement);
};
PagingContent.rootSelector = SELECTORS.ROOT;
/**
* Load content and create page.
*
* @param {Number} pageNumber
* @returns {*|Promise}
*/
PagingContent.prototype.createPage = function(pageNumber) {
return this.loadContent(pageNumber).then(function(html, js) {
Templates.appendNodeContents(this.root, html, js);
}.bind(this)).then(function() {
return this.findPage(pageNumber);
}.bind(this)
);
};
/**
* Find a page by the number.
*
* @param {Number} pageNumber The number of the page to be found.
* @returns {*} Page root
*/
PagingContent.prototype.findPage = function(pageNumber) {
return this.root.find('[data-page="' + pageNumber + '"]');
};
/**
* Make a page visible.
*
* @param {Number} pageNumber The number of the page to be visible.
*/
PagingContent.prototype.showPage = function(pageNumber) {
var existingPage = this.findPage(pageNumber);
this.root.find(SELECTORS.PAGE_REGION).addClass('hidden');
if (existingPage.length) {
existingPage.removeClass('hidden');
} else {
this.createPage(pageNumber).done(function(newPage) {
newPage.removeClass('hidden');
});
}
};
/**
* Event listeners.
*/
PagingContent.prototype.registerEventListeners = function() {
this.pagingBar.on(PagingBar.events.PAGE_SELECTED, function(e, data) {
if (!data.isSamePage) {
this.showPage(data.pageNumber);
}
}.bind(this));
};
return PagingContent;
});
+53
View File
@@ -0,0 +1,53 @@
// 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/>.
/**
* A javascript module to retrieve enrolled coruses from the server.
*
* @package block_myoverview
* @copyright 2018 Bas Brands <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/ajax'], function(Ajax) {
/**
* Retrieve a list of enrolled courses.
*
* Valid args are:
* string classification future, inprogress, past
* int limit number of records to retreive
* int Offset offset for pagination
* int sort sort by lastaccess or name
*
* @method getEnrolledCoursesByTimeline
* @param {object} args The request arguments
* @return {promise} Resolved with an array of courses
*/
var getEnrolledCoursesByTimeline = function(args) {
var request = {
methodname: 'core_course_get_enrolled_courses_by_timeline_classification',
args: args
};
var promise = Ajax.call([request])[0];
return promise;
};
return {
getEnrolledCoursesByTimeline: getEnrolledCoursesByTimeline
};
});
+188
View File
@@ -0,0 +1,188 @@
// 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/>.
/**
* Manage the courses view for the overview block.
*
* @package block_myoverview
* @copyright 2018 Bas Brands <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'core/notification',
'block_myoverview/repository',
'core/paged_content_factory',
'core/templates',
],
function(
$,
Notification,
Repository,
PagedContentFactory,
Templates
) {
var TEMPLATES = {
COURSES_CARDS: 'block_myoverview/view-cards',
COURSES_LIST: 'block_myoverview/view-list',
COURSES_SUMMARY: 'block_myoverview/view-summary',
NOCOURSES: 'block_myoverview/no-courses'
};
var NUMCOURSES_PERPAGE = [12, 24];
var currentCourseList = [];
/**
* Get filter values from DOM.
*
* @param {object} root The root element for the courses view.
* @return {filters} Set filters.
*/
var getFilterValues = function(root) {
var filters = {};
filters.display = root.attr('data-display');
filters.grouping = root.attr('data-grouping');
filters.sort = root.attr('data-sort');
return filters;
};
// We want the paged content controls below the paged content area
// and the controls should be ignored while data is loading.
var DEFAULT_PAGED_CONTENT_CONFIG = {
ignoreControlWhileLoading: true,
controlPlacementBottom: true,
};
/**
* Get enrolled courses from backend.
*
* @param {object} filters The filters for this view.
* @param {int} limit The number of courses to show.
* @param {int} pageNumber The pagenumber to view.
* @return {promise} Resolved with an array of courses.
*/
var getMyCourses = function(filters, limit, pageNumber) {
return Repository.getEnrolledCoursesByTimeline({
offset: pageNumber * limit,
limit: limit,
classification: filters.grouping,
sort: filters.sort
});
};
/**
* Render the dashboard courses.
*
* @param {object} root The root element for the courses view.
* @param {array} coursesData containing array of returned courses.
* @param {object} filters The filters for this view.
* @return {promise} jQuery promise resolved after rendering is complete.
*/
var renderCourses = function(root, coursesData, filters) {
var currentTemplate = '';
if (filters.display == 'cards') {
currentTemplate = TEMPLATES.COURSES_CARDS;
} else if (filters.display == 'list') {
currentTemplate = TEMPLATES.COURSES_LIST;
} else {
currentTemplate = TEMPLATES.COURSES_SUMMARY;
}
if (coursesData.courses.length) {
return Templates.render(currentTemplate, {
courses: coursesData.courses
});
} else {
var nocoursesimg = root.attr('data-nocoursesimg');
return Templates.render(TEMPLATES.NOCOURSES, {
nocoursesimg: nocoursesimg
});
}
};
/**
* Intialise the courses list and cards views on page load.
*
* @param {object} root The root element for the courses view.
* @param {object} content The content element for the courses view.
*/
var init = function(root, content) {
root = $(root);
var filters = getFilterValues(root);
var pagedContentPromise = PagedContentFactory.createWithLimit(
NUMCOURSES_PERPAGE,
function(pagesData, actions) {
var promises = [];
pagesData.forEach(function(pageData) {
var pageNumber = pageData.pageNumber - 1;
var pagePromise = getMyCourses(
filters,
pageData.limit,
pageNumber
).then(function(coursesData) {
if (coursesData.courses.length < pageData.limit) {
actions.allItemsLoaded(pageData.pageNumber);
}
currentCourseList = coursesData;
return renderCourses(root, coursesData, filters);
})
.catch(Notification.exception);
promises.push(pagePromise);
});
return promises;
},
DEFAULT_PAGED_CONTENT_CONFIG
);
pagedContentPromise.then(function(html, js) {
return Templates.replaceNodeContents(content, html, js);
}).catch(Notification.exception);
};
/**
* Reset the courses views to their original
* state on first page load.
*
* This is called when configuration has changed for the event lists
* to cause them to reload their data.
*
* @param {object} root The root element for the timeline view.
* @param {object} content The content element for the timeline view.
*/
var reset = function(root, content) {
var filters = getFilterValues(root);
renderCourses(root, currentCourseList, filters)
.then(function(html, js) {
return Templates.replaceNodeContents(content, html, js);
}).catch(Notification.exception);
};
return {
init: init,
reset: reset
};
});
+109
View File
@@ -0,0 +1,109 @@
// 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/>.
/**
* Manage the timeline view navigation for the overview block.
*
* @package block_myoverview
* @copyright 2018 Bas Brands <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(
[
'jquery',
'core/custom_interaction_events',
'block_myoverview/view'
],
function(
$,
CustomEvents,
View
) {
var SELECTORS = {
FILTERS: '[data-region="filter"]',
FILTER_OPTION: '[data-filter]',
DISPLAY_OPTION: '[data-display-option]'
};
/**
* Event listener for the Display filter (cards, list).
*
* @param {object} root The root element for the overview block
* @param {object} viewRoot The root element for displaying courses.
* @param {object} viewContent content The content element for the courses view.
*/
var registerSelector = function(root, viewRoot, viewContent) {
var Selector = root.find(SELECTORS.FILTERS);
CustomEvents.define(Selector, [CustomEvents.events.activate]);
Selector.on(
CustomEvents.events.activate,
SELECTORS.FILTER_OPTION,
function(e, data) {
var option = $(e.target);
if (option.hasClass('active')) {
// If it's already active then we don't need to do anything.
return;
}
var attributename = 'data-' + option.attr('data-filter');
viewRoot.attr(attributename, option.attr('data-value'));
// Reset the views.
View.init(viewRoot, viewContent);
data.originalEvent.preventDefault();
}
);
CustomEvents.define(Selector, [CustomEvents.events.activate]);
Selector.on(
CustomEvents.events.activate,
SELECTORS.DISPLAY_OPTION,
function(e, data) {
var option = $(e.target);
if (option.hasClass('active')) {
return;
}
viewRoot.attr('data-display', option.attr('data-value'));
View.reset(viewRoot, viewContent);
data.originalEvent.preventDefault();
}
);
};
/**
* Initialise the timeline view navigation by adding event listeners to
* the navigation elements.
*
* @param {object} root The root element for the myoverview block
* @param {object} viewRoot The root element for the myoverview block
* @param {object} viewContent The content element for the myoverview block
*/
var init = function(root, viewRoot, viewContent) {
root = $(root);
registerSelector(root, viewRoot, viewContent);
};
return {
init: init
};
});
@@ -1,189 +0,0 @@
<?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/>.
/**
* Class containing data for courses view in the myoverview block.
*
* @package block_myoverview
* @copyright 2017 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace block_myoverview\output;
defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
use core_course\external\course_summary_exporter;
/**
* Class containing data for courses view in the myoverview block.
*
* @copyright 2017 Simey Lameze <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class courses_view implements renderable, templatable {
/** Quantity of courses per page. */
const COURSES_PER_PAGE = 6;
/** @var array $courses List of courses the user is enrolled in. */
protected $courses = [];
/** @var array $coursesprogress List of progress percentage for each course. */
protected $coursesprogress = [];
/**
* The courses_view constructor.
*
* @param array $courses list of courses.
* @param array $coursesprogress list of courses progress.
*/
public function __construct($courses, $coursesprogress) {
$this->courses = $courses;
$this->coursesprogress = $coursesprogress;
}
/**
* Export this data so it can be used as the context for a mustache template.
*
* @param \renderer_base $output
* @return array
*/
public function export_for_template(renderer_base $output) {
global $CFG;
require_once($CFG->dirroot.'/course/lib.php');
// Build courses view data structure.
$coursesview = [
'hascourses' => !empty($this->courses)
];
// How many courses we have per status?
$coursesbystatus = ['past' => 0, 'inprogress' => 0, 'future' => 0];
foreach ($this->courses as $course) {
$courseid = $course->id;
$context = \context_course::instance($courseid);
$exporter = new course_summary_exporter($course, [
'context' => $context
]);
$exportedcourse = $exporter->export($output);
// Convert summary to plain text.
$exportedcourse->summary = content_to_text($exportedcourse->summary, $exportedcourse->summaryformat);
$course = new \core_course_list_element($course);
foreach ($course->get_course_overviewfiles() as $file) {
$isimage = $file->is_valid_image();
if ($isimage) {
$url = file_encode_url("$CFG->wwwroot/pluginfile.php",
'/'. $file->get_contextid(). '/'. $file->get_component(). '/'.
$file->get_filearea(). $file->get_filepath(). $file->get_filename(), !$isimage);
$exportedcourse->courseimage = $url;
$exportedcourse->classes = 'courseimage';
break;
}
}
$exportedcourse->color = $this->coursecolor($course->id);
if (!isset($exportedcourse->courseimage)) {
$pattern = new \core_geopattern();
$pattern->setColor($exportedcourse->color);
$pattern->patternbyid($courseid);
$exportedcourse->classes = 'coursepattern';
$exportedcourse->courseimage = $pattern->datauri();
}
// Include course visibility.
$exportedcourse->visible = (bool)$course->visible;
$courseprogress = null;
$classified = course_classify_for_timeline($course);
if (isset($this->coursesprogress[$courseid])) {
$courseprogress = $this->coursesprogress[$courseid]['progress'];
$exportedcourse->hasprogress = !is_null($courseprogress);
$exportedcourse->progress = $courseprogress;
}
if ($classified == COURSE_TIMELINE_PAST) {
// Courses that have already ended.
$pastpages = floor($coursesbystatus['past'] / $this::COURSES_PER_PAGE);
$coursesview['past']['pages'][$pastpages]['courses'][] = $exportedcourse;
$coursesview['past']['pages'][$pastpages]['active'] = ($pastpages == 0 ? true : false);
$coursesview['past']['pages'][$pastpages]['page'] = $pastpages + 1;
$coursesview['past']['haspages'] = true;
$coursesbystatus['past']++;
} else if ($classified == COURSE_TIMELINE_FUTURE) {
// Courses that have not started yet.
$futurepages = floor($coursesbystatus['future'] / $this::COURSES_PER_PAGE);
$coursesview['future']['pages'][$futurepages]['courses'][] = $exportedcourse;
$coursesview['future']['pages'][$futurepages]['active'] = ($futurepages == 0 ? true : false);
$coursesview['future']['pages'][$futurepages]['page'] = $futurepages + 1;
$coursesview['future']['haspages'] = true;
$coursesbystatus['future']++;
} else {
// Courses still in progress. Either their end date is not set, or the end date is not yet past the current date.
$inprogresspages = floor($coursesbystatus['inprogress'] / $this::COURSES_PER_PAGE);
$coursesview['inprogress']['pages'][$inprogresspages]['courses'][] = $exportedcourse;
$coursesview['inprogress']['pages'][$inprogresspages]['active'] = ($inprogresspages == 0 ? true : false);
$coursesview['inprogress']['pages'][$inprogresspages]['page'] = $inprogresspages + 1;
$coursesview['inprogress']['haspages'] = true;
$coursesbystatus['inprogress']++;
}
}
// Build courses view paging bar structure.
foreach ($coursesbystatus as $status => $total) {
$quantpages = ceil($total / $this::COURSES_PER_PAGE);
if ($quantpages) {
$coursesview[$status]['pagingbar']['disabled'] = ($quantpages <= 1);
$coursesview[$status]['pagingbar']['pagecount'] = $quantpages;
$coursesview[$status]['pagingbar']['first'] = ['page' => '&laquo;', 'url' => '#'];
$coursesview[$status]['pagingbar']['last'] = ['page' => '&raquo;', 'url' => '#'];
for ($page = 0; $page < $quantpages; $page++) {
$coursesview[$status]['pagingbar']['pages'][$page] = [
'number' => $page + 1,
'page' => $page + 1,
'url' => '#',
'active' => ($page == 0 ? true : false)
];
}
}
}
return $coursesview;
}
/**
* Generate a semi-random color based on the courseid number (so it will always return
* the same color for a course)
*
* @param int $courseid
* @return string $color, hexvalue color code.
*/
protected function coursecolor($courseid) {
// The colour palette is hardcoded for now. It would make sense to combine it with theme settings.
$basecolors = ['#81ecec', '#74b9ff', '#a29bfe', '#dfe6e9', '#00b894', '#0984e3', '#b2bec3', '#fdcb6e', '#fd79a8', '#6c5ce7'];
$color = $basecolors[$courseid % 10];
return $color;
}
}
+3 -31
View File
@@ -27,14 +27,13 @@ defined('MOODLE_INTERNAL') || die();
use renderable;
use renderer_base;
use templatable;
use core_completion\progress;
require_once($CFG->libdir . '/completionlib.php');
/**
* Class containing data for my overview block.
*
* @copyright 2017 Simey Lameze <simey@moodle.com>
* @copyright 2018 Bas Brands <bas@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class main implements renderable, templatable {
@@ -45,38 +44,11 @@ class main implements renderable, templatable {
* @return stdClass
*/
public function export_for_template(renderer_base $output) {
global $USER;
$courses = enrol_get_my_courses('*');
$coursesprogress = [];
foreach ($courses as $course) {
$completion = new \completion_info($course);
// First, let's make sure completion is enabled.
if (!$completion->is_enabled()) {
continue;
}
$percentage = progress::get_course_progress_percentage($course);
if (!is_null($percentage)) {
$percentage = floor($percentage);
}
$coursesprogress[$course->id]['completed'] = $completion->is_course_complete($USER->id);
$coursesprogress[$course->id]['progress'] = $percentage;
}
$coursesview = new courses_view($courses, $coursesprogress);
$nocoursesurl = $output->image_url('courses', 'block_myoverview')->out();
return [
'midnight' => usergetmidnight(time()),
'coursesview' => $coursesview->export_for_template($output),
'urls' => [
'nocourses' => $nocoursesurl,
],
return (object) [
'nocoursesimg' => $nocoursesurl
];
}
}
-41
View File
@@ -1,41 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* This file keeps track of upgrades to the myoverview block
*
* @package block_myoverview
* @copyright 2018 Ryan Wyllie <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Upgrade code for the myoverview block.
*
* @param int $oldversion
*/
function xmldb_block_myoverview_upgrade($oldversion) {
global $DB;
if ($oldversion < 2018092700) {
$DB->delete_records('user_preferences', ['name' => 'block_myoverview_last_tab']);
upgrade_block_savepoint(true, 2018092700, 'myoverview');
}
return true;
}
+35 -4
View File
@@ -22,17 +22,48 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['all'] = 'All';
$string['aria:allcourses'] = 'All courses';
$string['aria:card'] = 'Switch to card view';
$string['aria:controls'] = 'Course overview controls';
$string['aria:courseimage'] = 'Course image:';
$string['aria:coursename'] = 'Course name:';
$string['aria:coursesummary'] = 'Course summary text:';
$string['aria:courseprogress'] = 'Course progress:';
$string['aria:displaydropdown'] = 'Display dropdown';
$string['aria:future'] = 'Show future courses';
$string['aria:groupingdropdown'] = 'Grouping dropdown';
$string['aria:inprogress'] = 'Show in courses in progress';
$string['aria:lastaccessed'] = 'Sort courses by last accessed date';
$string['aria:list'] = 'Switch to list view';
$string['aria:title'] = 'Sort courses by title';
$string['aria:past'] = 'Show past courses';
$string['aria:summary'] = 'Switch to summary view';
$string['aria:sortingdropdown'] = 'Sorting dropdown';
$string['card'] = 'Card';
$string['courseprogress'] = 'Course progress:';
$string['complete'] = 'Complete';
$string['favorite'] = 'Favorite';
$string['future'] = 'Future';
$string['future:aria'] = 'View future courses';
$string['hidden'] = 'Hidden';
$string['inprogress'] = 'In progress';
$string['inprogress:aria'] = 'View in progress courses';
$string['lastaccessed'] = 'Last accessed';
$string['lastaccessed:aria'] = 'Sort course by lastaccessed';
$string['list'] = 'List';
$string['morecourses'] = 'More courses';
$string['myoverview:addinstance'] = 'Add a new course overview block';
$string['myoverview:myaddinstance'] = 'Add a new course overview block to Dashboard';
$string['nocourses'] = 'No courses';
$string['nocoursesinprogress'] = 'No in progress courses';
$string['nocoursesfuture'] = 'No future courses';
$string['nocoursesinprogress'] = 'No in progress courses';
$string['nocourses'] = 'No courses';
$string['nocoursespast'] = 'No past courses';
$string['past'] = 'Past';
$string['pluginname'] = 'Course overview';
$string['viewcourse'] = 'View course';
$string['viewcoursename'] = 'View course {$a}';
$string['privacy:metadata'] = 'The myoverview block does not store any personal data.';
$string['summary'] = 'Summary';
$string['title'] = 'Title';
$string['viewcoursename'] = 'View course {$a}';
$string['viewcourse'] = 'View course';
@@ -1,47 +0,0 @@
{{!
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 block_myoverview/course-paging-content-item
This template renders each course block.
Example context (json):
{
"page": 1,
"active": true,
"courses": [
{
"fullnamedisplay": "course 1",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
},
{
"fullnamedisplay": "course 2",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
}
]
}
}}
{{< block_myoverview/paging-content-item }}
{{$classes}}row card-deck{{/classes}}
{{$content}}
{{#courses}}
{{> block_myoverview/courses-view-course-item }}
{{/courses}}
{{/content}}
{{/ block_myoverview/paging-content-item }}
@@ -1,48 +0,0 @@
{{!
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 block_myoverview/course-paging-content
This template renders the each course block containing a summary and calendar events.
Example context (json):
{
"pages": [
{
"page": 1,
"active": true,
"courses": [
{
"fullnamedisplay": "course 1",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
},
{
"fullnamedisplay": "course 2",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
}
]
}
]
}
}}
{{< block_myoverview/paging-content }}
{{$paging-content-item}}
{{> block_myoverview/course-paging-content-item }}
{{/paging-content-item}}
{{/ block_myoverview/paging-content }}
@@ -1,45 +0,0 @@
{{!
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 block_myoverview/courses-view-by-status
This template renders the courses view for the myoverview block.
Example context (json):
{}
}}
<div id="{{$id}}courses-view-status-{{uniqid}}{{/id}}"
data-status="{{$status}}{{/status}}">
{{> block_myoverview/course-paging-content }}
<div class="text-xs-center text-center">
{{> block_myoverview/paging-bar }}
</div>
</div>
{{#js}}
require(['jquery', 'block_myoverview/paging_bar', 'block_myoverview/paging_content'],
function($, PagingBar, PagingContent) {
var root = $('#{{$id}}courses-view-status-{{uniqid}}{{/id}}');
var pagingBarElement = root.find(PagingBar.rootSelector);
var pagingContentElement = root.find(PagingContent.rootSelector);
var content = new PagingContent(pagingContentElement, pagingBarElement);
content.registerEventListeners();
});
{{/js}}
@@ -1,49 +0,0 @@
{{!
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 block_myoverview/courses-view-course-item
This template renders the course summary (view by courses) for the myoverview block.
Example context (json):
{
"fullnamedisplay": "course 3",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
}
}}
<div class="card mb-3 courses-view-course-item">
<a href="{{viewurl}}">
<div class="card-img-top myoverviewimg {{classes}}" style='background-image: url("{{{courseimage}}}");'>
</div>
</a>
<div class="card-body course-info-container" id="course-info-container-{{id}}">
<div class="media">
<div class="mr-2">
{{> block_myoverview/progress-chart}}
</div>
<div class="media-body">
<h4 class="h5"><a href="{{viewurl}}" class="{{^visible}}dimmed{{/visible}}">{{{fullnamedisplay}}}</a></h4>
</div>
</div>
<p class="text-muted">
{{#shortentext}} 140, {{summary}}{{/shortentext}}
</p>
</div>
</div>
@@ -1,40 +0,0 @@
{{!
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 block_myoverview/courses-view-nav-grouping-display-filter
This template renders the main content area for the myoverview block.
Example context (json):
{}
}}
<div data-region="courses-grouping-display-filter" class="btn-group">
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{#str}} inprogress, block_myoverview {{/str}}
</button>
<div class="dropdown-menu list-group hidden" data-show-active-item data-skip-active-class="true">
<a class="dropdown-item active" href="#myoverview_courses_view_in_progress" data-toggle="tab">
{{#str}} inprogress, block_myoverview {{/str}}
</a>
<a class="dropdown-item" href="#myoverview_courses_view_future" data-toggle="tab">
{{#str}} future, block_myoverview {{/str}}
</a>
<a class="dropdown-item" href="#myoverview_courses_view_past" data-toggle="tab">
{{#str}} past, block_myoverview {{/str}}
</a>
</div>
</div>
@@ -20,77 +20,24 @@
This template renders the courses view for the myoverview block.
Example context (json):
{}
{
"nocoursesimg": "https://moodlesite/theme/image.php/boost/block_myoverview/1535727318/courses"
}
}}
<div id="courses-view-{{uniqid}}" data-region="courses-view">
{{#hascourses}}
<div class="tab-content">
<div class="tab-pane active fade show" id="myoverview_courses_view_in_progress">
{{#inprogress}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-in-progress{{/id}}
{{$status}}1{{/status}}
{{$pagingbarid}}pb-for-in-progress{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/inprogress}}
{{^inprogress}}
<div class="justify-content-center text-center mt-5">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursesinprogress, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted mt-3">{{#str}} nocoursesinprogress, block_myoverview {{/str}}</p>
</div>
{{/inprogress}}
</div>
<div class="tab-pane fade" id="myoverview_courses_view_future">
{{#future}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-future{{/id}}
{{$status}}2{{/status}}
{{$pagingbarid}}pb-for-future{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/future}}
{{^future}}
<div class="justify-content-center text-center mt-5">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursesfuture, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted mt-3">{{#str}} nocoursesfuture, block_myoverview {{/str}}</p>
</div>
{{/future}}
</div>
<div class="tab-pane fade" id="myoverview_courses_view_past">
{{#past}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-past{{/id}}
{{$status}}0{{/status}}
{{$pagingbarid}}pb-for-past{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/past}}
{{^past}}
<div class="justify-content-center text-center mt-5">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursespast, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted mt-3">{{#str}} nocoursespast, block_myoverview {{/str}}</p>
</div>
{{/past}}
<div id="courses-view-{{uniqid}}"
data-region="courses-view"
data-display="cards"
data-grouping="all"
data-sort="fullname"
data-nocoursesimg="{{nocoursesimg}}">
<div data-region="course-view-content">
<div data-region="courses-loading-placeholder">
<div class="row card-deck">
{{> block_myoverview/placeholder-course }}
{{> block_myoverview/placeholder-course }}
{{> block_myoverview/placeholder-course }}
{{> block_myoverview/placeholder-course }}
</div>
</div>
</div>
{{/hascourses}}
{{^hascourses}}
<div class="justify-content-center text-center mt-5">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocourses, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted mt-3">{{#str}} nocourses, block_myoverview {{/str}}</p>
</div>
{{/hascourses}}
</div>
</div>
+25 -15
View File
@@ -23,21 +23,31 @@
{}
}}
<div id="block-myoverview-{{uniqid}}" class="block-myoverview" data-region="myoverview">
<div class="container p-0 m-b-1">
<div class="row no-gutters">
{{#coursesview}}
{{#hascourses}}
<div class="{{#viewingtimeline}}d-none{{/viewingtimeline}}" data-tab-content="courses">
{{> block_myoverview/courses-view-nav-grouping-display-filter }}
</div>
{{/hascourses}}
{{/coursesview}}
</div>
</div>
<div class="container p-0">
{{#coursesview}}
<div id="block-myoverview-{{uniqid}}" class="block-myoverview" data-region="myoverview" role="navigation">
<div data-region="filter" class="d-flex m-b-1" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
{{> block_myoverview/nav-grouping-selector }}
{{> block_myoverview/nav-sort-selector }}
{{> block_myoverview/nav-display-selector }}
</div>
<div class="container-fluid p-0">
{{> block_myoverview/courses-view }}
{{/coursesview}}
</div>
</div>
{{#js}}
require(
[
'jquery',
'block_myoverview/main',
],
function(
$,
Main
) {
var root = $('#block-myoverview-{{uniqid}}');
Main.init(root);
});
{{/js}}
@@ -0,0 +1,47 @@
{{!
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 block_myoverview/nav-display-selector
This template renders display dropdown.
Example context (json):
{}
}}
<div class="dropdown">
<button id="displaydropdown" type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
aria-label="{{#str}} aria:displaydropdown, block_myoverview {{/str}}">
<span class="d-sm-inline-block">{{#pix}} a/view_icon_active {{/pix}}</span>
</button>
<ul class="dropdown-menu" data-show-active-item aria-labelledby="displaydropdown">
<li>
<a class="dropdown-item active" href="#" data-display-option="display" data-value="cards" aria-label="{{#str}} aria:card, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} card, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-display-option="display" data-value="list" aria-label="{{#str}} aria:list, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} list, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-display-option="display" data-value="summary" aria-label="{{#str}} aria:summary, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} summary, block_myoverview {{/str}}
</a>
</li>
</ul>
</div>
@@ -0,0 +1,51 @@
{{!
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 block_myoverview/nav-grouping-selector
This template renders grouping dropdown.
Example context (json):
{}
}}
<div class="dropdown">
<button id="groupingdropdown" type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="{{#str}} aria:groupingdropdown, block_myoverview {{/str}}">
<span class="d-sm-inline-block">{{#str}} all, block_myoverview {{/str}}</span>
</button>
<ul class="dropdown-menu" data-show-active-item aria-labelledby="groupingdropdown">
<li>
<a class="dropdown-item active" href="#" data-filter="grouping" data-value="all" aria-label="{{#str}} aria:allcourses, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} all, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-filter="grouping" data-value="inprogress" aria-label="{{#str}} aria:inprogress, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} inprogress, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-filter="grouping" data-value="future" aria-label="{{#str}} aria:future, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} future, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-filter="grouping" data-value="past" aria-label="{{#str}} aria:past, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} past, block_myoverview {{/str}}
</a>
</li>
</ul>
</div>
@@ -0,0 +1,43 @@
{{!
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 block_myoverview/nav-sort-selector
This template renders sorting dropdown.
Example context (json):
{}
}}
<div class="dropdown mr-1 ml-auto">
{{#str}} sortby, core {{/str}}
<button id="sortingdropdown" type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" aria-label="{{#str}} aria:sortingdropdown, block_myoverview {{/str}}">
<span class="d-sm-inline-block">{{#str}} title, block_myoverview {{/str}}</span>
</button>
<ul class="dropdown-menu" data-show-active-item aria-labelledby="sortingdropdown">
<li>
<a class="dropdown-item active" href="#" data-filter="sort" data-value="fullname" aria-label="{{#str}} aria:title, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} title, block_myoverview {{/str}}
</a>
</li>
<li>
<a class="dropdown-item" href="#" data-filter="sort" data-value="ul.timeaccess desc" aria-label="{{#str}} aria:lastaccessed, block_myoverview {{/str}}" aria-controls="courses-view-{{uniqid}}">
{{#str}} lastaccessed, block_myoverview {{/str}}
</a>
</li>
</ul>
</div>
@@ -15,27 +15,19 @@
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_myoverview/paging-bar-item
@template block_myoverview/no-courses
This template renders a single item in the paging bar.
This template renders the no courses message.
Example context (json):
{
"url": "#",
"number": 1,
"page": "1",
"active": true
"nocoursesimg": "https://moodlesite/theme/image.php/boost/block_myoverview/1535727318/courses"
}
}}
<li class="page-item {{#active}}active{{/active}} {{#disabled}}disabled{{/disabled}}"
data-region="page-item"
data-page-number="{{$pagenumber}}{{number}}{{/pagenumber}}">
<a href="{{url}}"
class="page-link"
data-region="page-link">
{{$item-content}}
{{{page}}}
{{/item-content}}
</a>
</li>
<div class="text-xs-center text-center m-t-3" data-region="empty-message">
<img class="empty-placeholder-image-lg"
src="{{nocoursesimg}}"
alt="{{#str}} nocourses, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted mt-3">{{#str}} nocourses, block_myoverview {{/str}}</p>
</div>
@@ -1,96 +0,0 @@
{{!
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 block_myoverview/paging-bar
This template renders the bootstrap style paging bar.
Example context (json):
{
"pagingbar": {
"pagecount": 2,
"previous": {},
"next": {},
"first": {
"url": "#",
"page": "first"
},
"last": {
"url": "#",
"page": "last"
},
"pages": [
{
"url": "#",
"number": 1,
"page": "1",
"active": true
},
{
"url": "#",
"number": 2,
"page": "2"
}
]
}
}
}}
{{#pagingbar}}
<nav aria-label="{{label}}"
id="{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}"
data-region="paging-bar"
data-page-count="{{pagecount}}">
<ul class="pagination">
{{#previous}}
{{< block_myoverview/paging-bar-item }}
{{$item-content}}
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">{{#str}}previous{{/str}}</span>
{{/item-content}}
{{/ block_myoverview/paging-bar-item }}
{{/previous}}
{{#first}}
{{< block_myoverview/paging-bar-item }}
{{$pagenumber}}first{{/pagenumber}}
{{/ block_myoverview/paging-bar-item }}
{{/first}}
{{#pages}}
{{> block_myoverview/paging-bar-item }}
{{/pages}}
{{#last}}
{{< block_myoverview/paging-bar-item }}
{{$pagenumber}}last{{/pagenumber}}
{{/ block_myoverview/paging-bar-item }}
{{/last}}
{{#next}}
{{< block_myoverview/paging-bar-item }}
{{$item-content}}
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">{{#str}}next{{/str}}</span>
{{/item-content}}
{{/ block_myoverview/paging-bar-item }}
{{/next}}
</ul>
</nav>
{{#js}}
require(['jquery', 'block_myoverview/paging_bar'], function($, PagingBar) {
var root = $('#{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}');
PagingBar.registerEventListeners(root);
});
{{/js}}
{{/pagingbar}}
@@ -1,44 +0,0 @@
{{!
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 block_myoverview/paging-content
This template renders each of the content regions for a paginated
content section.
Example context (json):
{
"pages": [
{
"active": true,
"page": 1,
"content": "<p>Some page content</p>"
},
{
"page": 2,
"content": "<p>Some page content</p>"
}
]
}
}}
<div id="{{$pagingcontentid}}paging-content-{{uniqid}}{{/pagingcontentid}}" data-region="paging-content">
{{#pages}}
{{$paging-content-item}}
{{> block_myoverview/paging-content-item }}
{{/paging-content-item}}
{{/pages}}
</div>
@@ -15,22 +15,19 @@
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_myoverview/paging-content-item
@template block_myoverview/placeholder-course
This template renders the content of a page. It is to be used with
the paging bar to toggle visibility of the content items.
This template renders an course card item loading placeholder for the myoverview block.
Example context (json):
{
"active": true,
"page": 1,
"content": "<p>Some page content</p>"
}
{}
}}
<div data-region="paging-content-item"
data-page="{{page}}"
class="row-fluid {{^active}}hidden{{/active}} {{$classes}}{{/classes}}">
{{$content}}
{{{content}}}
{{/content}}
</div>
<div class="card course-card border-0">
<div class="card-img-top bg-pulse-grey w-100" style="height: 7rem">
</div>
<div class="card-body course-info-container">
<div class="bg-pulse-grey w-100 m-b-3" style="height: 1rem"></div>
</div>
<div class="bg-pulse-grey w-100" style="height: 3rem">
</div>
</div>
@@ -15,22 +15,20 @@
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template block_myoverview/paging-content-item
@template block_myoverview/progress-bar
This template renders the content of a page. It is to be used with
the paging bar to toggle visibility of the content items.
This template renders a simple progress bar.
Example context (json):
{
"active": true,
"page": 1,
"content": "<p>Some page content</p>"
"progress": 50
}
}}
<div data-region="paging-content-item"
data-page="{{page}}"
class="{{^active}}hidden{{/active}} {{$classes}}{{/classes}}">
{{$content}}
{{{content}}}
{{/content}}
<div class="progress">
<div class="progress-bar bar" role="progressbar" aria-valuenow="{{progress}}" style="width: {{progress}}%" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="small">
<span class="sr-only">{{#str}}aria:courseprogress, block_myoverview{{/str}}</span>
<strong>{{progress}}%</strong> {{#str}}complete, block_myoverview{{/str}}
</div>
@@ -1,50 +0,0 @@
{{!
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 block_myoverview/progress-chart
This template renders a doughnut chart to show course progress.
Example context (json):
{
"hasprogress": true,
"progress": "60"
}
}}
<div class="progress-chart-container m-b-1">
{{#hasprogress}}
<div class="progress-doughnut">
<div class="progress-text {{#progress}}has-percent{{/progress}}">{{progress}}&#37;</div>
<div class="progress-indicator">
<svg xmlns="http://www.w3.org/2000/svg">
<g>
<title aria-hidden="true">{{progress}}&#37;</title>
<circle class="circle percent-{{progress}}"
r="27.5"
cx="35"
cy="35"/>
</g>
</svg>
</div>
</div>
{{/hasprogress}}
{{^hasprogress}}
<div class="no-progress">
{{#pix}} i/course {{/pix}}
</div>
{{/hasprogress}}
</div>
@@ -0,0 +1,62 @@
{{!
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 block_myoverview/view-cards
This template renders the cards view for the myoverview block.
Example context (json):
{
"courses": [
{
"name": "Assignment due 1",
"viewurl": "https://moodlesite/course/view.php?id=2",
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
"progress": 10
}
]
}
}}
<div class="row card-deck" role="list">
{{#courses}}
<div class="card course-card" role="listitem">
<a href="{{viewurl}}" tabindex="-1" role="presentation">
<div class="card-img-top myoverviewimg" style='background-image: url("{{{courseimage}}}");'>
<span class="sr-only">{{#str}}aria:courseimage, block_myoverview{{/str}}</span>
</div>
</a>
<div class="card-body course-info-container" id="course-info-container-{{id}}">
<div class="d-flex">
<div class="card-title">
<a href="{{viewurl}}">
<span class="sr-only">{{#str}}aria:coursename, block_myoverview{{/str}}</span>
{{#shortentext}}140, {{{fullname}}} {{/shortentext}}
</a>
</div>
</div>
</div>
{{#hasprogress}}
<div class="card-footer course-card-footer">
{{> block_myoverview/progress-bar}}
</div>
{{/hasprogress}}
</div>
{{/courses}}
</div>
@@ -0,0 +1,55 @@
{{!
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 block_myoverview/view-list
This template renders the list view for the myoverview block.
Example context (json):
{
"courses": [
{
"name": "Assignment due 1",
"viewurl": "https://moodlesite/course/view.php?id=2",
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"hasprogress": true,
"progress": 10
}
]
}
}}
<ul class="list-group" role="list">
{{#courses}}
<li class="list-group-item course-listitem" role="listitem">
<div class="row-fluid">
<div class="{{#hasprogress}}col-6 span6{{/hasprogress}}{{^hasprogress}}col-12 span12{{/hasprogress}}">
<a href="{{viewurl}}">
<span class="sr-only">{{#str}}aria:coursename, block_myoverview{{/str}}</span>
{{{fullname}}}
</a>
</div>
{{#hasprogress}}
<div class="col-6 span6">
{{> block_myoverview/progress-bar}}
</div>
{{/hasprogress}}
</div>
</li>
{{/courses}}
</ul>
@@ -0,0 +1,62 @@
{{!
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 block_myoverview/view-summary
This template renders the list view for the myoverview block.
Example context (json):
{
"courses": [
{
"name": "Assignment due 1",
"viewurl": "https://moodlesite/course/view.php?id=2",
"courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg",
"fullname": "course 3",
"summary": "This course is about assignments",
"hasprogress": true,
"progress": 10
}
]
}
}}
<div role="list">
{{#courses}}
<div class="course-summaryitem m-b-1 p-2" role="listitem">
<div class="row-fluid d-flex">
<a href="{{viewurl}}" class="col-sm-4 col-xl-3 span4" tabindex="-1" role="presentation">
<img src="{{{courseimage}}}" class="summaryimage img-fluid" alt="{{#str}}aria:courseimage, block_myoverview{{/str}}">
</a>
<div class="col-sm-8 col-xl-9 span8 align-self-stretch d-flex flex-column">
<a href="{{viewurl}}">
<span class="sr-only">{{#str}}aria:coursename, block_myoverview{{/str}}</span>
<h4>{{{fullname}}}</h4>
</a>
<div class="summary">
<span class="sr-only">{{#str}}aria:coursesummary, block_myoverview{{/str}}</span>
{{{summary}}}
</div>
<div class="ml-auto mt-auto w-50 p-t-1">
{{#hasprogress}}
{{> block_myoverview/progress-bar}}
{{/hasprogress}}
</div>
</div>
</div>
</div>
{{/courses}}
</div>
@@ -7,30 +7,62 @@ Feature: The my overview block allows users to easily access their courses
Background:
Given the following "users" exist:
| username | firstname | lastname | email | idnumber |
| student1 | Student | 1 | student1@example.com | S1 |
| student2 | Student | 2 | student2@example.com | S2 |
| student1 | Student | X | student1@example.com | S1 |
And the following "courses" exist:
| fullname | shortname | category | startdate | enddate |
| Course 1 | C1 | 0 | ##1 month ago## | ##15 days ago## |
| Course 2 | C2 | 0 | ##yesterday## | ##tomorrow## |
| Course 3 | C3 | 0 | ##first day of next month## | ##last day of next month## |
| Course 3 | C3 | 0 | ##yesterday## | ##tomorrow## |
| Course 4 | C4 | 0 | ##yesterday## | ##tomorrow## |
| Course 5 | C5 | 0 | ##first day of next month## | ##last day of next month## |
And the following "course enrolments" exist:
| user | course | role |
| student1 | C1 | student |
| student1 | C2 | student |
| student1 | C3 | student |
| student1 | C4 | student |
| student1 | C5 | student |
Scenario: See the courses I am enrolled by their status on courses view
Scenario: View past courses
Given I log in as "student1"
And I should see "Course 2" in the "Course overview" "block"
And I should not see "Course 1" in the "Course overview" "block"
And I click on "In progress" "button" in the "Course overview" "block"
And I click on "Future" "link" in the "Course overview" "block"
And I should see "Course 3" in the "Course overview" "block"
And I should not see "Course 1" in the "Course overview" "block"
And I click on "Future" "button" in the "Course overview" "block"
And I click on "All" "button" in the "Course overview" "block"
When I click on "Past" "link" in the "Course overview" "block"
Then I should see "Course 1" in the "Course overview" "block"
And I should not see "Course 2" in the "Course overview" "block"
And I should not see "Course 3" in the "Course overview" "block"
And I should not see "Course 4" in the "Course overview" "block"
And I should not see "Course 5" in the "Course overview" "block"
And I log out
Scenario: View future courses
Given I log in as "student1"
And I click on "All" "button" in the "Course overview" "block"
When I click on "Future" "link" in the "Course overview" "block"
Then I should see "Course 5" in the "Course overview" "block"
And I should not see "Course 1" in the "Course overview" "block"
And I should not see "Course 2" in the "Course overview" "block"
And I should not see "Course 3" in the "Course overview" "block"
And I should not see "Course 4" in the "Course overview" "block"
And I log out
Scenario: View inprogress courses
Given I log in as "student1"
And I click on "All" "button" in the "Course overview" "block"
When I click on "In progress" "link" in the "Course overview" "block"
Then I should see "Course 2" in the "Course overview" "block"
Then I should see "Course 3" in the "Course overview" "block"
Then I should see "Course 4" in the "Course overview" "block"
And I should not see "Course 1" in the "Course overview" "block"
And I should not see "Course 5" in the "Course overview" "block"
And I log out
Scenario: View all courses
Given I log in as "student1"
And I click on "All" "button" in the "Course overview" "block"
When I click on "All" "link" in the "Course overview" "block"
Then I should see "Course 1" in the "Course overview" "block"
Then I should see "Course 2" in the "Course overview" "block"
Then I should see "Course 3" in the "Course overview" "block"
Then I should see "Course 4" in the "Course overview" "block"
Then I should see "Course 5" in the "Course overview" "block"
And I log out
@@ -20,6 +20,13 @@ Feature: Course overview block show users their progress on courses
| teacher1 | C1 | editingteacher |
| student1 | C1 | student |
Scenario: Course progress percentage should not be displayed if completion is not enabled
Given I log in as "student1"
And I click on "All" "button" in the "Course overview" "block"
When I click on "All" "link" in the "Course overview" "block"
Then I should not see "0%" in the "Course overview" "block"
And I log out
Scenario: User complete activity and verify his progress
Given I log in as "teacher1"
And I am on "Course 1" course homepage with editing mode on
@@ -30,12 +37,13 @@ Feature: Course overview block show users their progress on courses
| id_completionview | 1 |
And I press "Save and return to course"
And I log out
And I log in as "student1"
When I log in as "student1"
And I click on "All" "button" in the "Course overview" "block"
Then I should see "Course 1" in the "Course overview" "block"
And I should see "0%" in the "Course overview" "block"
And I am on "Course 1" course homepage
And I follow "Test choice 1"
And I follow "Dashboard" in the user menu
And I should see "Course 1" in the "Course overview" "block"
And I click on "All" "button" in the "Course overview" "block"
And I should see "100%" in the "Course overview" "block"
And I log out
+1 -1
View File
@@ -24,6 +24,6 @@
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2018092700; // The current plugin version (Date: YYYYMMDDXX).
$plugin->version = 2018100100; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2018050800; // Requires this Moodle version.
$plugin->component = 'block_myoverview'; // Full name of the plugin (used for diagnostics).
+88 -1
View File
@@ -41,9 +41,22 @@ class course_summary_exporter extends \core\external\exporter {
}
protected function get_other_values(renderer_base $output) {
$courseimage = self::get_course_image($this->data);
if (!$courseimage) {
$courseimage = self::get_course_pattern($this->data);
}
$progress = self::get_course_progress($this->data);
$hasprogress = false;
if ($progress === 0 || $progress > 0) {
$hasprogress = true;
}
$progress = floor($progress);
return array(
'fullnamedisplay' => get_course_display_name_for_list($this->data),
'viewurl' => (new moodle_url('/course/view.php', array('id' => $this->data->id)))->out(false)
'viewurl' => (new moodle_url('/course/view.php', array('id' => $this->data->id)))->out(false),
'courseimage' => $courseimage,
'progress' => $progress,
'hasprogress' => $hasprogress
);
}
@@ -96,7 +109,81 @@ class course_summary_exporter extends \core\external\exporter {
),
'viewurl' => array(
'type' => PARAM_URL,
),
'courseimage' => array(
'type' => PARAM_RAW,
),
'progress' => array(
'type' => PARAM_INT,
'optional' => true
),
'hasprogress' => array(
'type' => PARAM_BOOL
)
);
}
/**
* Get the course image if added to course.
*
* @param object $course
* @return string url of course image
*/
public static function get_course_image($course) {
global $CFG;
$courseinlist = new \core_course_list_element($course);
foreach ($courseinlist->get_course_overviewfiles() as $file) {
if ($file->is_valid_image()) {
$pathcomponents = [
'/pluginfile.php',
$file->get_contextid(),
$file->get_component(),
$file->get_filearea() . $file->get_filepath() . $file->get_filename()
];
$path = implode('/', $pathcomponents);
return (new moodle_url($path))->out();
}
}
return false;
}
/**
* Get the course pattern datauri.
*
* The datauri is an encoded svg that can be passed as a url.
* @param object $course
* @return string datauri
*/
public static function get_course_pattern($course) {
$color = self::coursecolor($course->id);
$pattern = new \core_geopattern();
$pattern->setColor($color);
$pattern->patternbyid($course->id);
return $pattern->datauri();
}
/**
* Get the course progress percentage.
*
* @param object $course
* @return int progress
*/
public static function get_course_progress($course) {
return \core_completion\progress::get_course_progress_percentage($course);
}
/**
* Get the course color.
*
* @param int $courseid
* @return string hex color code.
*/
public static function coursecolor($courseid) {
// The colour palette is hardcoded for now. It would make sense to combine it with theme settings.
$basecolors = ['#81ecec', '#74b9ff', '#a29bfe', '#dfe6e9', '#00b894',
'#0984e3', '#b2bec3', '#fdcb6e', '#fd79a8', '#6c5ce7'];
$color = $basecolors[$courseid % 10];
return $color;
}
}
+2
View File
@@ -3654,6 +3654,8 @@ class core_course_external extends external_api {
$sort = $params['sort'];
switch($classification) {
case COURSE_TIMELINE_ALL:
break;
case COURSE_TIMELINE_PAST:
break;
case COURSE_TIMELINE_INPROGRESS:
+5 -3
View File
@@ -55,6 +55,7 @@ define('FIRSTUSEDEXCELROW', 3);
define('MOD_CLASS_ACTIVITY', 0);
define('MOD_CLASS_RESOURCE', 1);
define('COURSE_TIMELINE_ALL', 'all');
define('COURSE_TIMELINE_PAST', 'past');
define('COURSE_TIMELINE_INPROGRESS', 'inprogress');
define('COURSE_TIMELINE_FUTURE', 'future');
@@ -4204,8 +4205,9 @@ function course_filter_courses_by_timeline_classification(
int $limit = 0
) : array {
if (!in_array($classification, [COURSE_TIMELINE_PAST, COURSE_TIMELINE_INPROGRESS, COURSE_TIMELINE_FUTURE])) {
$message = 'Classification must be one of COURSE_TIMELINE_PAST, '
if (!in_array($classification,
[COURSE_TIMELINE_ALL, COURSE_TIMELINE_PAST, COURSE_TIMELINE_INPROGRESS, COURSE_TIMELINE_FUTURE])) {
$message = 'Classification must be one of COURSE_TIMELINE_ALL, COURSE_TIMELINE_PAST, '
. 'COURSE_TIMELINE_INPROGRESS or COURSE_TIMELINE_FUTURE';
throw new moodle_exception($message);
}
@@ -4217,7 +4219,7 @@ function course_filter_courses_by_timeline_classification(
foreach ($courses as $course) {
$numberofcoursesprocessed++;
if ($classification == course_classify_for_timeline($course)) {
if ($classification == COURSE_TIMELINE_ALL || $classification == course_classify_for_timeline($course)) {
$filteredcourses[] = $course;
$filtermatches++;
}
+60
View File
@@ -2556,6 +2556,66 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
'expectedcourses' => ['cfuture', 'dfuture', 'efuture'],
'expectednextoffset' => 15
],
'all no limit or offset' => [
'coursedata' => $coursedata,
'classification' => 'all',
'limit' => 0,
'offset' => 0,
'expectedcourses' => [
'afuture',
'ainprogress',
'apast',
'bfuture',
'binprogress',
'bpast',
'cfuture',
'cinprogress',
'cpast',
'dfuture',
'dinprogress',
'dpast',
'efuture',
'einprogress',
'epast'
],
'expectednextoffset' => 15
],
'all limit no offset' => [
'coursedata' => $coursedata,
'classification' => 'all',
'limit' => 5,
'offset' => 0,
'expectedcourses' => [
'afuture',
'ainprogress',
'apast',
'bfuture',
'binprogress'
],
'expectednextoffset' => 5
],
'all limit and offset' => [
'coursedata' => $coursedata,
'classification' => 'all',
'limit' => 5,
'offset' => 5,
'expectedcourses' => [
'bpast',
'cfuture',
'cinprogress',
'cpast',
'dfuture'
],
'expectednextoffset' => 10
],
'all offset past result set' => [
'coursedata' => $coursedata,
'classification' => 'all',
'limit' => 5,
'offset' => 50,
'expectedcourses' => [],
'expectednextoffset' => 50
],
];
}
+182
View File
@@ -792,4 +792,186 @@ class core_enrollib_testcase extends advanced_testcase {
// There are still only two distinct users.
$this->assertEquals(2, count_enrolled_users($context));
}
/**
* Test cases for the test_enrol_get_my_courses_sort_by_last_access test.
*/
public function get_enrol_get_my_courses_sort_by_last_access_test_cases() {
$now = time();
$enrolledcoursesdata = [
['shortname' => 'a', 'lastaccess' => $now - 2],
['shortname' => 'b', 'lastaccess' => $now - 1],
['shortname' => 'c', 'lastaccess' => $now],
['shortname' => 'd', 'lastaccess' => $now - 1],
['shortname' => 'e']
];
$unenrolledcoursesdata = [
['shortname' => 'x', 'lastaccess' => $now - 2],
['shortname' => 'y', 'lastaccess' => $now - 1],
['shortname' => 'z', 'lastaccess' => $now]
];
return [
'empty set' => [
'enrolledcoursesdata' => [],
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => []
],
'ul.timeaccess asc, shortname asc no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc, shortname asc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['e', 'a', 'b', 'd', 'c']
],
'ul.timeaccess asc, shortname asc with limit no offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc, shortname asc',
'limit' => 2,
'offset' => 0,
'expectedcourses' => ['e', 'a']
],
'ul.timeaccess asc, shortname asc with limit and offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc, shortname asc',
'limit' => 2,
'offset' => 2,
'expectedcourses' => ['b', 'd']
],
'ul.timeaccess asc, shortname asc with limit and offset beyond end of data set' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc, shortname asc',
'limit' => 2,
'offset' => 4,
'expectedcourses' => ['c']
],
'ul.timeaccess desc, shortname asc no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess desc, shortname asc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['c', 'b', 'd', 'a', 'e']
],
'ul.timeaccess desc, shortname desc, no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess desc, shortname desc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['c', 'd', 'b', 'a', 'e']
],
'ul.timeaccess asc, shortname desc, no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'ul.timeaccess asc, shortname desc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['e', 'a', 'd', 'b', 'c']
],
'shortname asc, no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'shortname asc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['a', 'b', 'c', 'd', 'e']
],
'shortname desc, no limit or offset' => [
'enrolledcoursesdata' => $enrolledcoursesdata,
'unenrolledcoursesdata' => $unenrolledcoursesdata,
'sort' => 'shortname desc',
'limit' => 0,
'offset' => 0,
'expectedcourses' => ['e', 'd', 'c', 'b', 'a']
],
];
}
/**
* Test the get_enrolled_courses_by_timeline_classification function.
*
* @dataProvider get_enrol_get_my_courses_sort_by_last_access_test_cases()
* @param array $enrolledcoursesdata Courses to create and enrol the user in
* @param array $unenrolledcoursesdata Courses to create nut not enrol the user in
* @param string $sort Sort string for the enrol function
* @param int $limit Maximum number of results
* @param int $offset Offset the courses result set by this amount
* @param array $expectedcourses Expected courses in result
*/
public function test_enrol_get_my_courses_sort_by_last_access(
$enrolledcoursesdata,
$unenrolledcoursesdata,
$sort,
$limit,
$offset,
$expectedcourses
) {
global $DB, $CFG;
$this->resetAfterTest();
$generator = $this->getDataGenerator();
$student = $generator->create_user();
$lastaccessrecords = [];
foreach ($enrolledcoursesdata as $coursedata) {
$lastaccess = null;
if (isset($coursedata['lastaccess'])) {
$lastaccess = $coursedata['lastaccess'];
unset($coursedata['lastaccess']);
}
$course = $generator->create_course($coursedata);
$generator->enrol_user($student->id, $course->id, 'student');
if (!is_null($lastaccess)) {
$lastaccessrecords[] = [
'userid' => $student->id,
'courseid' => $course->id,
'timeaccess' => $lastaccess
];
}
}
foreach ($unenrolledcoursesdata as $coursedata) {
$lastaccess = null;
if (isset($coursedata['lastaccess'])) {
$lastaccess = $coursedata['lastaccess'];
unset($coursedata['lastaccess']);
}
$course = $generator->create_course($coursedata);
if (!is_null($lastaccess)) {
$lastaccessrecords[] = [
'userid' => $student->id,
'courseid' => $course->id,
'timeaccess' => $lastaccess
];
}
}
if (!empty($lastaccessrecords)) {
$DB->insert_records('user_lastaccess', $lastaccessrecords);
}
$this->setUser($student);
$result = enrol_get_my_courses('shortname', $sort, $limit, [], false, $offset);
$actual = array_map(function($course) {
return $course->shortname;
}, array_values($result));
$this->assertEquals($expectedcourses, $actual);
}
}
+34 -7
View File
@@ -554,6 +554,8 @@ function enrol_add_course_navigation(navigation_node $coursenode, $course) {
*
* @param string|array $fields Extra fields to be returned (array or comma-separated list).
* @param string|null $sort Comma separated list of fields to sort by, defaults to respecting navsortmycoursessort.
* Allowed prefixes for sort fields are: "ul" for the user_lastaccess table, "c" for the courses table,
* "ue" for the user_enrolments table.
* @param int $limit max number of courses
* @param array $courseids the list of course ids to filter by
* @param bool $allaccessible Include courses user is not enrolled in, but can access
@@ -599,17 +601,32 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
$orderby = "";
$sort = trim($sort);
$sorttimeaccess = false;
$allowedsortprefixes = array('c', 'ul', 'ue');
if (!empty($sort)) {
$rawsorts = explode(',', $sort);
$sorts = array();
foreach ($rawsorts as $rawsort) {
$rawsort = trim($rawsort);
if (strpos($rawsort, 'c.') === 0) {
$rawsort = substr($rawsort, 2);
if (preg_match('/^ul\.(\S*)\s(asc|desc)/i', $rawsort, $matches)) {
if (strcasecmp($matches[2], 'asc') == 0) {
$sorts[] = 'COALESCE(ul.' . $matches[1] . ', 0) ASC';
} else {
$sorts[] = 'COALESCE(ul.' . $matches[1] . ', 0) DESC';
}
$sorttimeaccess = true;
} else if (strpos($rawsort, '.') !== false) {
$prefix = explode('.', $rawsort);
if (in_array($prefix[0], $allowedsortprefixes)) {
$sorts[] = trim($rawsort);
} else {
throw new coding_exception('Invalid $sort parameter in enrol_get_my_courses()');
}
} else {
$sorts[] = 'c.'.trim($rawsort);
}
$sorts[] = trim($rawsort);
}
$sort = 'c.'.implode(',c.', $sorts);
$sort = implode(',', $sorts);
$orderby = "ORDER BY $sort";
}
@@ -628,6 +645,9 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
$params['contextlevel'] = CONTEXT_COURSE;
$wheres = implode(" AND ", $wheres);
$timeaccessselect = "";
$timeaccessjoin = "";
if (!empty($courseids)) {
list($courseidssql, $courseidsparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED);
$wheres = sprintf("%s AND c.id %s", $wheres, $courseidssql);
@@ -640,14 +660,20 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
$courseidsql .= "
SELECT DISTINCT e.courseid
FROM {enrol} e
JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid)
JOIN {user_enrolments} ue ON (ue.enrolid = e.id AND ue.userid = :userid1)
WHERE ue.status = :active AND e.status = :enabled AND ue.timestart < :now1
AND (ue.timeend = 0 OR ue.timeend > :now2)";
$params['userid'] = $USER->id;
$params['userid1'] = $USER->id;
$params['active'] = ENROL_USER_ACTIVE;
$params['enabled'] = ENROL_INSTANCE_ENABLED;
$params['now1'] = round(time(), -2); // Improves db caching.
$params['now2'] = $params['now1'];
if ($sorttimeaccess) {
$params['userid2'] = $USER->id;
$timeaccessselect = ', ul.timeaccess as lastaccessed';
$timeaccessjoin = "LEFT JOIN {user_lastaccess} ul ON (ul.courseid = c.id AND ul.userid = :userid2)";
}
}
// When including non-enrolled but accessible courses...
@@ -708,9 +734,10 @@ function enrol_get_my_courses($fields = null, $sort = null, $limit = 0, $coursei
// Note: we can not use DISTINCT + text fields due to Oracle and MS limitations, that is why
// we have the subselect there.
$sql = "SELECT $coursefields $ccselect
$sql = "SELECT $coursefields $ccselect $timeaccessselect
FROM {course} c
JOIN ($courseidsql) en ON (en.courseid = c.id)
$timeaccessjoin
$ccjoin
WHERE $wheres
$orderby";
+81 -100
View File
@@ -72,113 +72,94 @@ $blocks-plus-gutter: $blocks-column-width + ( $grid-gutter-width / 2 );
}
}
$chart-size: 70px;
$doughnut-border-size: 15px;
$doughnut-dasharray: 173;
$doughnut-empty-colour: $gray-lighter;
$doughnut-fill-colour: $brand-warning;
.progress-chart-container {
height: $chart-size;
width: $chart-size;
.progress-doughnut {
position: relative;
height: $chart-size;
width: $chart-size;
background-clip: padding-box;
border: $doughnut-border-size solid $doughnut-empty-colour;
border-radius: 50%;
box-sizing: border-box;
.progress-text {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
transform: translate(-50%, -50%);
color: $doughnut-empty-colour;
&.has-percent {
color: $doughnut-fill-colour;
}
}
.progress-indicator {
position: absolute;
top: ($doughnut-border-size * -1);
left: ($doughnut-border-size * -1);
height: $chart-size;
width: $chart-size;
svg {
position: relative;
height: 100%;
width: 100%;
.circle {
stroke-width: $doughnut-border-size;
stroke: $doughnut-fill-colour;
fill: none;
stroke-dasharray: $doughnut-dasharray;
stroke-dashoffset: $doughnut-dasharray;
transform: rotate(-90deg);
transform-origin: center center;
@for $i from 1 through 100 {
&.percent-#{$i} {
stroke-dashoffset: $doughnut-dasharray - ($i / 100 * $doughnut-dasharray);
}
}
}
}
}
}
.no-progress {
height: $chart-size;
width: $chart-size;
background-color: $doughnut-empty-colour;
border-radius: 50%;
position: relative;
.icon {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
margin: 0;
transform: translate(-63%, -50%);
color: #fff;
height: ($chart-size / 2) + 10px;
width: ($chart-size / 2) + 10px;
font-size: ($chart-size / 2) + 10px;
}
}
}
$card-gutter : $card-deck-margin * 2;
.block_myoverview {
.empty-placeholder-image-sm {
height: 50px;
}
.empty-placeholder-image-lg {
height: 125px;
}
}
.card-deck {
.card {
$card-gutter : $card-deck-margin * 2;
flex-grow: 0;
flex-shrink: 0;
flex-basis: calc(50% - #{$card-gutter});
.course-card {
margin-bottom: $card-gutter;
flex-basis: 100%;
}
.course-info-container {
padding: 0.8rem;
}
.course-card-footer {
padding: 0.8rem;
}
.progress {
height: 0.5rem;
}
.myoverviewimg {
height: 150px;
&.courseimage {
background-position: center;
background-size: cover;
height: 7rem;
background-position: center;
background-size: cover;
}
.course-summaryitem {
border: $border-width solid $border-color;
background-color: $body-bg;
}
.summary img {
max-width: 100%;
}
@include media-breakpoint-down(sm) {
.summaryimage {
max-height: 7rem;
}
}
}
#region-main {
.block_myoverview {
.course-card {
flex-grow: 0;
flex-shrink: 0;
flex-basis: calc(50% - #{$card-gutter});
}
@include media-breakpoint-up(sm) {
.course-card {
flex-basis: calc(50% - #{$card-gutter});
}
}
@include media-breakpoint-up(md) {
.course-card {
flex-basis: calc(33.33% - #{$card-gutter});
}
}
@include media-breakpoint-up(lg) {
.course-card {
flex-basis: calc(25% - #{$card-gutter});
}
}
@include media-breakpoint-up(xl) {
.course-card {
flex-basis: calc(20% - #{$card-gutter});
}
}
}
}
#region-main.has-blocks .block_myoverview {
@include media-breakpoint-up(lg) {
.course-card {
flex-basis: calc(33.33% - #{$card-gutter});
}
}
@include media-breakpoint-up(xl) {
.course-card {
flex-basis: calc(25% - #{$card-gutter});
}
}
}
body.drawer-open-left #region-main.has-blocks .block_myoverview {
.course-card {
flex-basis: calc(50% - #{$card-gutter});
}
@include media-breakpoint-up(lg) {
.course-card {
flex-basis: calc(33.33% - #{$card-gutter});
}
}
}
+2
View File
@@ -58,6 +58,8 @@ $breadcrumb-divider-rtl: "/" !default;
// Alerts
$alert-border-width: 0 !default;
$card-group-margin: .25rem;
$theme-colors: (
primary: $primary,
secondary: $gray-200,
+67 -272
View File
@@ -5576,25 +5576,25 @@ tbody.collapse.show {
display: flex;
flex-direction: column; }
.card-deck .card, .card-deck #page-enrol-users #filterform, #page-enrol-users .card-deck #filterform, .card-deck .que .history, .que .card-deck .history, .card-deck .userprofile .profile_tree section, .userprofile .profile_tree .card-deck section, .card-deck .groupinfobox, .card-deck .well {
margin-bottom: 15px; }
margin-bottom: 0.25rem; }
@media (min-width: 576px) {
.card-deck {
flex-flow: row wrap;
margin-right: -15px;
margin-left: -15px; }
margin-right: -0.25rem;
margin-left: -0.25rem; }
.card-deck .card, .card-deck #page-enrol-users #filterform, #page-enrol-users .card-deck #filterform, .card-deck .que .history, .que .card-deck .history, .card-deck .userprofile .profile_tree section, .userprofile .profile_tree .card-deck section, .card-deck .groupinfobox, .card-deck .well {
display: flex;
flex: 1 0 0%;
flex-direction: column;
margin-right: 15px;
margin-right: 0.25rem;
margin-bottom: 0;
margin-left: 15px; } }
margin-left: 0.25rem; } }
.card-group {
display: flex;
flex-direction: column; }
.card-group > .card, #page-enrol-users .card-group > #filterform, .que .card-group > .history, .userprofile .profile_tree .card-group > section, .card-group > .groupinfobox, .card-group > .well {
margin-bottom: 15px; }
margin-bottom: 0.25rem; }
@media (min-width: 576px) {
.card-group {
flex-flow: row wrap; }
@@ -11131,278 +11131,73 @@ div.editor_atto_toolbar button .icon {
[data-region="blocks-column"] {
width: 100%; } }
.progress-chart-container {
height: 70px;
width: 70px; }
.progress-chart-container .progress-doughnut {
position: relative;
height: 70px;
width: 70px;
background-clip: padding-box;
border: 15px solid #dee2e6;
border-radius: 50%;
box-sizing: border-box; }
.progress-chart-container .progress-doughnut .progress-text {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
transform: translate(-50%, -50%);
color: #dee2e6; }
.progress-chart-container .progress-doughnut .progress-text.has-percent {
color: #ff7518; }
.progress-chart-container .progress-doughnut .progress-indicator {
position: absolute;
top: -15px;
left: -15px;
height: 70px;
width: 70px; }
.progress-chart-container .progress-doughnut .progress-indicator svg {
position: relative;
height: 100%;
width: 100%; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle {
stroke-width: 15px;
stroke: #ff7518;
fill: none;
stroke-dasharray: 173;
stroke-dashoffset: 173;
transform: rotate(-90deg);
transform-origin: center center; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-1 {
stroke-dashoffset: 171.27; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-2 {
stroke-dashoffset: 169.54; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-3 {
stroke-dashoffset: 167.81; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-4 {
stroke-dashoffset: 166.08; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-5 {
stroke-dashoffset: 164.35; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-6 {
stroke-dashoffset: 162.62; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-7 {
stroke-dashoffset: 160.89; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-8 {
stroke-dashoffset: 159.16; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-9 {
stroke-dashoffset: 157.43; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-10 {
stroke-dashoffset: 155.7; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-11 {
stroke-dashoffset: 153.97; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-12 {
stroke-dashoffset: 152.24; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-13 {
stroke-dashoffset: 150.51; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-14 {
stroke-dashoffset: 148.78; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-15 {
stroke-dashoffset: 147.05; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-16 {
stroke-dashoffset: 145.32; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-17 {
stroke-dashoffset: 143.59; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-18 {
stroke-dashoffset: 141.86; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-19 {
stroke-dashoffset: 140.13; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-20 {
stroke-dashoffset: 138.4; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-21 {
stroke-dashoffset: 136.67; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-22 {
stroke-dashoffset: 134.94; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-23 {
stroke-dashoffset: 133.21; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-24 {
stroke-dashoffset: 131.48; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-25 {
stroke-dashoffset: 129.75; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-26 {
stroke-dashoffset: 128.02; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-27 {
stroke-dashoffset: 126.29; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-28 {
stroke-dashoffset: 124.56; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-29 {
stroke-dashoffset: 122.83; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-30 {
stroke-dashoffset: 121.1; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-31 {
stroke-dashoffset: 119.37; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-32 {
stroke-dashoffset: 117.64; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-33 {
stroke-dashoffset: 115.91; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-34 {
stroke-dashoffset: 114.18; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-35 {
stroke-dashoffset: 112.45; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-36 {
stroke-dashoffset: 110.72; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-37 {
stroke-dashoffset: 108.99; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-38 {
stroke-dashoffset: 107.26; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-39 {
stroke-dashoffset: 105.53; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-40 {
stroke-dashoffset: 103.8; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-41 {
stroke-dashoffset: 102.07; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-42 {
stroke-dashoffset: 100.34; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-43 {
stroke-dashoffset: 98.61; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-44 {
stroke-dashoffset: 96.88; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-45 {
stroke-dashoffset: 95.15; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-46 {
stroke-dashoffset: 93.42; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-47 {
stroke-dashoffset: 91.69; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-48 {
stroke-dashoffset: 89.96; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-49 {
stroke-dashoffset: 88.23; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-50 {
stroke-dashoffset: 86.5; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-51 {
stroke-dashoffset: 84.77; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-52 {
stroke-dashoffset: 83.04; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-53 {
stroke-dashoffset: 81.31; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-54 {
stroke-dashoffset: 79.58; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-55 {
stroke-dashoffset: 77.85; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-56 {
stroke-dashoffset: 76.12; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-57 {
stroke-dashoffset: 74.39; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-58 {
stroke-dashoffset: 72.66; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-59 {
stroke-dashoffset: 70.93; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-60 {
stroke-dashoffset: 69.2; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-61 {
stroke-dashoffset: 67.47; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-62 {
stroke-dashoffset: 65.74; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-63 {
stroke-dashoffset: 64.01; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-64 {
stroke-dashoffset: 62.28; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-65 {
stroke-dashoffset: 60.55; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-66 {
stroke-dashoffset: 58.82; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-67 {
stroke-dashoffset: 57.09; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-68 {
stroke-dashoffset: 55.36; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-69 {
stroke-dashoffset: 53.63; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-70 {
stroke-dashoffset: 51.9; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-71 {
stroke-dashoffset: 50.17; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-72 {
stroke-dashoffset: 48.44; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-73 {
stroke-dashoffset: 46.71; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-74 {
stroke-dashoffset: 44.98; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-75 {
stroke-dashoffset: 43.25; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-76 {
stroke-dashoffset: 41.52; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-77 {
stroke-dashoffset: 39.79; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-78 {
stroke-dashoffset: 38.06; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-79 {
stroke-dashoffset: 36.33; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-80 {
stroke-dashoffset: 34.6; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-81 {
stroke-dashoffset: 32.87; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-82 {
stroke-dashoffset: 31.14; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-83 {
stroke-dashoffset: 29.41; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-84 {
stroke-dashoffset: 27.68; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-85 {
stroke-dashoffset: 25.95; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-86 {
stroke-dashoffset: 24.22; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-87 {
stroke-dashoffset: 22.49; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-88 {
stroke-dashoffset: 20.76; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-89 {
stroke-dashoffset: 19.03; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-90 {
stroke-dashoffset: 17.3; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-91 {
stroke-dashoffset: 15.57; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-92 {
stroke-dashoffset: 13.84; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-93 {
stroke-dashoffset: 12.11; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-94 {
stroke-dashoffset: 10.38; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-95 {
stroke-dashoffset: 8.65; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-96 {
stroke-dashoffset: 6.92; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-97 {
stroke-dashoffset: 5.19; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-98 {
stroke-dashoffset: 3.46; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-99 {
stroke-dashoffset: 1.73; }
.progress-chart-container .progress-doughnut .progress-indicator svg .circle.percent-100 {
stroke-dashoffset: 0; }
.progress-chart-container .no-progress {
height: 70px;
width: 70px;
background-color: #dee2e6;
border-radius: 50%;
position: relative; }
.progress-chart-container .no-progress .icon {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
margin: 0;
transform: translate(-63%, -50%);
color: #fff;
height: 45px;
width: 45px;
font-size: 45px; }
.block_myoverview .empty-placeholder-image-sm {
height: 50px; }
.block_myoverview .empty-placeholder-image-lg {
height: 125px; }
.card-deck .card, .card-deck #page-enrol-users #filterform, #page-enrol-users .card-deck #filterform, .card-deck .que .history, .que .card-deck .history, .card-deck .userprofile .profile_tree section, .userprofile .profile_tree .card-deck section, .card-deck .groupinfobox, .card-deck .well {
.block_myoverview .course-card {
margin-bottom: 0.5rem;
flex-basis: 100%; }
.block_myoverview .course-info-container {
padding: 0.8rem; }
.block_myoverview .course-card-footer {
padding: 0.8rem; }
.block_myoverview .progress {
height: 0.5rem; }
.block_myoverview .myoverviewimg {
height: 7rem;
background-position: center;
background-size: cover; }
.block_myoverview .course-summaryitem {
border: 1px solid #dee2e6;
background-color: #fff; }
.block_myoverview .summary img {
max-width: 100%; }
@media (max-width: 767.98px) {
.block_myoverview .summaryimage {
max-height: 7rem; } }
#region-main .block_myoverview .course-card {
flex-grow: 0;
flex-shrink: 0;
flex-basis: calc(50% - 30px); }
flex-basis: calc(50% - 0.5rem); }
.card-deck .myoverviewimg {
height: 150px; }
.card-deck .myoverviewimg.courseimage {
background-position: center;
background-size: cover; }
@media (min-width: 576px) {
#region-main .block_myoverview .course-card {
flex-basis: calc(50% - 0.5rem); } }
@media (min-width: 768px) {
#region-main .block_myoverview .course-card {
flex-basis: calc(33.33% - 0.5rem); } }
@media (min-width: 992px) {
#region-main .block_myoverview .course-card {
flex-basis: calc(25% - 0.5rem); } }
@media (min-width: 1200px) {
#region-main .block_myoverview .course-card {
flex-basis: calc(20% - 0.5rem); } }
@media (min-width: 992px) {
#region-main.has-blocks .block_myoverview .course-card {
flex-basis: calc(33.33% - 0.5rem); } }
@media (min-width: 1200px) {
#region-main.has-blocks .block_myoverview .course-card {
flex-basis: calc(25% - 0.5rem); } }
body.drawer-open-left #region-main.has-blocks .block_myoverview .course-card {
flex-basis: calc(50% - 0.5rem); }
@media (min-width: 992px) {
body.drawer-open-left #region-main.has-blocks .block_myoverview .course-card {
flex-basis: calc(33.33% - 0.5rem); } }
.block_settings .block_tree [aria-expanded="true"],
.block_settings .block_tree [aria-expanded="true"].emptybranch,
+73 -26
View File
@@ -341,39 +341,86 @@
}
.block_myoverview {
background-color: transparent;
.row-fluid [class*="span"] {
margin-left: 0;
*,
*::before,
*::after {
box-sizing: border-box;
}
.empty-placeholder-image-sm {
height: 50px;
}
.empty-placeholder-image-lg {
height: 125px;
}
.courses-view-course-item {
height: 220px;
overflow-y: hidden;
.course-card {
.border-radius(@baseBorderRadius);
margin-bottom: 0.5rem;
flex-grow: 0;
flex-shrink: 0;
flex-basis: ~"calc(50% - 0.6rem)";
}
h4 {
font-weight: normal;
.course-info-container {
flex: 1 1 auto;
padding: 0.8rem;
}
.well {
background-color: @white;
box-shadow: none;
margin: 0 5px 10px;
.course-card-footer {
padding: 0.8rem;
background-color: @wellBackground;
border-top: 1px solid darken(@wellBackground, 7%);
.border-bottom-radius(@baseBorderRadius);
}
.progress {
height: 0.5rem;
margin-bottom: 0;
}
.myoverviewimg {
height: 150px;
&.courseimage {
background-position: center;
background-size: cover;
height: 7rem;
background-position: center;
background-size: cover;
.border-top-radius(@baseBorderRadius);
}
.list-group {
margin: 0;
}
.course-listitem {
display: block;
padding: 0.75rem 1.25rem;
margin-bottom: 0.5rem;
background-color: @white;
border: 1px solid @tableBorder;
.border-radius(@baseBorderRadius);
}
.course-summaryitem {
padding: 0.5rem;
background-color: @white;
border: 1px solid @tableBorder;
.border-radius(@baseBorderRadius);
}
.summary img {
max-width: 100%;
}
@media (max-width: 576px) {
.summaryimage {
max-height: 7rem;
}
}
}
@media (min-width: 576px) {
.card-deck {
display: flex;
flex-flow: row wrap;
margin-right: -.25rem;
margin-left: -.25rem;
}
.course-card {
display: flex;
flex-direction: column;
margin-right: 0.25rem;
margin-left: 0.25rem;
}
}
@media (min-width: 1200px) {
.course-card {
flex-basis: ~"calc(33% - 0.5rem)";
}
}
}
@@ -324,3 +324,23 @@
.w-25 {
width: 25%;
}
.d-flex {
display: flex !important;
}
.flex-column {
flex-direction: column !important;
}
.align-self-stretch {
align-self: stretch;
}
.ml-auto {
margin-left: auto;
}
.mt-auto {
margin-top: auto;
}
+99 -20
View File
@@ -16536,36 +16536,100 @@ body {
height: 35px;
width: 35px;
}
.block_myoverview {
background-color: transparent;
}
.block_myoverview .row-fluid [class*="span"] {
margin-left: 0;
}
.block_myoverview .empty-placeholder-image-sm {
height: 50px;
.block_myoverview *,
.block_myoverview *::before,
.block_myoverview *::after {
box-sizing: border-box;
}
.block_myoverview .empty-placeholder-image-lg {
height: 125px;
}
.block_myoverview .courses-view-course-item {
height: 220px;
overflow-y: hidden;
.block_myoverview .course-card {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
margin-bottom: 0.5rem;
flex-grow: 0;
flex-shrink: 0;
flex-basis: calc(50% - 0.6rem);
}
.block_myoverview h4 {
font-weight: normal;
.block_myoverview .course-info-container {
flex: 1 1 auto;
padding: 0.8rem;
}
.block_myoverview .well {
background-color: #fff;
box-shadow: none;
margin: 0 5px 10px;
.block_myoverview .course-card-footer {
padding: 0.8rem;
background-color: #f5f5f5;
border-top: 1px solid #e3e3e3;
-webkit-border-bottom-right-radius: 4px;
-moz-border-radius-bottomright: 4px;
border-bottom-right-radius: 4px;
-webkit-border-bottom-left-radius: 4px;
-moz-border-radius-bottomleft: 4px;
border-bottom-left-radius: 4px;
}
.block_myoverview .progress {
height: 0.5rem;
margin-bottom: 0;
}
.block_myoverview .myoverviewimg {
height: 150px;
}
.block_myoverview .myoverviewimg.courseimage {
height: 7rem;
background-position: center;
background-size: cover;
-webkit-border-top-right-radius: 4px;
-moz-border-radius-topright: 4px;
border-top-right-radius: 4px;
-webkit-border-top-left-radius: 4px;
-moz-border-radius-topleft: 4px;
border-top-left-radius: 4px;
}
.block_myoverview .list-group {
margin: 0;
}
.block_myoverview .course-listitem {
display: block;
padding: 0.75rem 1.25rem;
margin-bottom: 0.5rem;
background-color: #fff;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.block_myoverview .course-summaryitem {
padding: 0.5rem;
background-color: #fff;
border: 1px solid #ddd;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.block_myoverview .summary img {
max-width: 100%;
}
@media (max-width: 576px) {
.block_myoverview .summaryimage {
max-height: 7rem;
}
}
@media (min-width: 576px) {
.block_myoverview .card-deck {
display: flex;
flex-flow: row wrap;
margin-right: -0.25rem;
margin-left: -0.25rem;
}
.block_myoverview .course-card {
display: flex;
flex-direction: column;
margin-right: 0.25rem;
margin-left: 0.25rem;
}
}
@media (min-width: 1200px) {
.block_myoverview .course-card {
flex-basis: calc(33% - 0.5rem);
}
}
/**
* Moodle forms HTML isn't changeable via renderers (yet?) so this
@@ -22107,3 +22171,18 @@ ul.indented-list {
.w-25 {
width: 25%;
}
.d-flex {
display: flex !important;
}
.flex-column {
flex-direction: column !important;
}
.align-self-stretch {
align-self: stretch;
}
.ml-auto {
margin-left: auto;
}
.mt-auto {
margin-top: auto;
}
@@ -1,47 +0,0 @@
{{!
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 block_myoverview/course-paging-content-item
This template renders each course block.
Example context (json):
{
"page": 1,
"active": true,
"courses": [
{
"fullnamedisplay": "course 1",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
},
{
"fullnamedisplay": "course 2",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
}
]
}
}}
{{< block_myoverview/paging-content-item }}
{{$content}}
{{#courses}}
{{> block_myoverview/courses-view-course-item }}
{{/courses}}
<div class="clearfix"></div>
{{/content}}
{{/ block_myoverview/paging-content-item }}
@@ -1,53 +0,0 @@
{{!
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 block_myoverview/course-view-course-item
This template renders the course summary (view by courses) for the myoverview block.
Example context (json):
{
"shortname": "course 3",
"viewurl": "https://www.google.com",
"summary": "It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout."
}
}}
<div class="span6">
<div class="well well-small">
<a href="{{viewurl}}">
<div class="myoverviewimg m-b-1 {{classes}}" style='background-image: url("{{{courseimage}}}");'>
</div>
</a>
<div class="course-info-container" id="course-info-container-{{id}}">
<div class="media">
<div class="pull-left">
<div class="media-object">
{{> block_myoverview/progress-chart}}
</div>
</div>
<div class="media-body">
<h4 class="media-heading">
<a href="{{viewurl}}" class="{{^visible}}dimmed{{/visible}}">{{{fullnamedisplay}}}</a>
</h4>
</div>
</div>
<p class="text-muted">
{{#shortentext}} 140, {{{summary}}}{{/shortentext}}
</p>
</div>
</div>
</div>
@@ -1,41 +0,0 @@
{{!
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 block_myoverview/courses-view-nav-grouping-display-filter
This template renders the main content area for the myoverview block.
Example context (json):
{}
}}
<div data-region="courses-grouping-display-filter" class="btn-group">
<button type="button" class="btn btn-outline-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span data-active-item-text>{{#str}} inprogress, block_myoverview {{/str}}</span>
<span data-region="caret" class="caret"></span>
</button>
<ul class="dropdown-menu" data-show-active-item>
<li class="dropdown-item active" data-target="#myoverview_courses_view_in_progress" data-toggle="tab">
<a tabindex="-1" href="#">{{#str}} inprogress, block_myoverview {{/str}}</a>
</li>
<li class="dropdown-item" data-target="#myoverview_courses_view_future" data-toggle="tab">
<a tabindex="-1" href="#">{{#str}} future, block_myoverview {{/str}}</a>
</li>
<li class="dropdown-item" data-target="#myoverview_courses_view_past" data-toggle="tab">
<a tabindex="-1" href="#">{{#str}} past, block_myoverview {{/str}}</a>
</li>
</ul>
</div>
@@ -1,105 +0,0 @@
{{!
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 block_myoverview/courses-view
This template renders the courses view for the myoverview block.
Example context (json):
{}
}}
<div id="courses-view-{{uniqid}}" data-region="courses-view">
{{#hascourses}}
<div class="tab-content">
<div class="tab-pane active fade in" id="myoverview_courses_view_in_progress">
{{#inprogress}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-in-progress{{/id}}
{{$status}}1{{/status}}
{{$pagingbarid}}pb-for-in-progress{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/inprogress}}
{{^inprogress}}
<div class="text-xs-center text-center m-t-3">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursesinprogress, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted m-t-1">{{#str}} nocoursesinprogress, block_myoverview {{/str}}</p>
</div>
{{/inprogress}}
</div>
<div class="tab-pane fade" id="myoverview_courses_view_future">
{{#future}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-future{{/id}}
{{$status}}2{{/status}}
{{$pagingbarid}}pb-for-future{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/future}}
{{^future}}
<div class="text-xs-center text-center m-t-3">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursesfuture, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted m-t-1">{{#str}} nocoursesfuture, block_myoverview {{/str}}</p>
</div>
{{/future}}
</div>
<div class="tab-pane fade" id="myoverview_courses_view_past">
{{#past}}
{{< block_myoverview/courses-view-by-status }}
{{$id}}courses-view-past{{/id}}
{{$status}}0{{/status}}
{{$pagingbarid}}pb-for-past{{/pagingbarid}}
{{$pagingcontentid}}pc-for-in-progress{{/pagingcontentid}}
{{/ block_myoverview/courses-view-by-status }}
{{/past}}
{{^past}}
<div class="text-xs-center text-center m-t-3">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocoursespast, block_myoverview {{/str}}"
role="presentation">
<p class="text-muted m-t-1">{{#str}} nocoursespast, block_myoverview {{/str}}</p>
</div>
{{/past}}
</div>
</div>
{{/hascourses}}
{{^hascourses}}
<div class="text-xs-center text-center m-t-3">
<img class="empty-placeholder-image-lg"
src="{{urls.nocourses}}"
alt="{{#str}} nocourses, block_myoverview {{/str}}">
<p class="text-muted m-t-1">{{#str}} nocourses, block_myoverview {{/str}}</p>
</div>
{{/hascourses}}
</div>
{{#js}}
require(['jquery', 'core/custom_interaction_events'], function($, customEvents) {
var root = $('#courses-view-{{uniqid}}');
customEvents.define(root, [customEvents.events.activate]);
root.on(customEvents.events.activate, '[data-toggle="btns"] > .btn', function(e) {
root.find('.btn.active').removeClass('active');
$(e.target).closest('.btn').addClass('active');
});
});
{{/js}}
@@ -1,43 +0,0 @@
{{!
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 block_myoverview/main
This template renders the main content area for the myoverview block.
Example context (json):
{}
}}
<div id="block-myoverview-{{uniqid}}" class="block-myoverview" data-region="myoverview">
<div class="container-fluid p-0 m-b-1">
<div class="row-fluid no-gutters">
{{#coursesview}}
{{#hascourses}}
<div class="{{#viewingtimeline}}d-none{{/viewingtimeline}}" data-tab-content="courses">
{{> block_myoverview/courses-view-nav-grouping-display-filter }}
</div>
{{/hascourses}}
{{/coursesview}}
</div>
</div>
<div class="container-fluid p-0">
{{#coursesview}}
{{> block_myoverview/courses-view }}
{{/coursesview}}
</div>
</div>
@@ -1,97 +0,0 @@
{{!
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 block_myoverview/paging-bar
This template renders the bootstrap style paging bar.
Example context (json):
{
"pagingbar": {
"pagecount": 2,
"previous": {},
"next": {},
"first": {
"url": "#",
"page": "first"
},
"last": {
"url": "#",
"page": "last"
},
"pages": [
{
"url": "#",
"number": 1,
"page": "1",
"active": true
},
{
"url": "#",
"number": 2,
"page": "2"
}
]
}
}
}}
{{#pagingbar}}
<div aria-label="{{label}}"
id="{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}"
class="pagination"
data-region="paging-bar"
data-page-count="{{pagecount}}">
<ul>
{{#previous}}
{{< block_myoverview/paging-bar-item }}
{{$item-content}}
<span aria-hidden="true">&laquo;</span>
<span class="sr-only">{{#str}}previous{{/str}}</span>
{{/item-content}}
{{/ block_myoverview/paging-bar-item }}
{{/previous}}
{{#first}}
{{< block_myoverview/paging-bar-item }}
{{$pagenumber}}first{{/pagenumber}}
{{/ block_myoverview/paging-bar-item }}
{{/first}}
{{#pages}}
{{> block_myoverview/paging-bar-item }}
{{/pages}}
{{#last}}
{{< block_myoverview/paging-bar-item }}
{{$pagenumber}}last{{/pagenumber}}
{{/ block_myoverview/paging-bar-item }}
{{/last}}
{{#next}}
{{< block_myoverview/paging-bar-item }}
{{$item-content}}
<span aria-hidden="true">&raquo;</span>
<span class="sr-only">{{#str}}next{{/str}}</span>
{{/item-content}}
{{/ block_myoverview/paging-bar-item }}
{{/next}}
</ul>
</div>
{{#js}}
require(['jquery', 'block_myoverview/paging_bar'], function($, PagingBar) {
var root = $('#{{$pagingbarid}}paging-bar-{{uniqid}}{{/pagingbarid}}');
PagingBar.registerEventListeners(root);
});
{{/js}}
{{/pagingbar}}