mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 04:30:15 +01:00
Merge branch 'MDL-60474-master' of git://github.com/damyon/moodle
This commit is contained in:
commit
e63084ec1b
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
define(["jquery","core/notification","core/ajax","core/templates"],function(a,b,c,d){var e=function(b){this._regionSelector=b,this._region=a(b),this._userCache={},a(document).on("user-changed",this._refreshUserInfo.bind(this))};return e.prototype._regionSelector=null,e.prototype._userCache=null,e.prototype._region=null,e.prototype._lastUserId=0,e.prototype._getAssignmentId=function(){return this._region.attr("data-assignmentid")},e.prototype._refreshUserInfo=function(e,f){var g=a.Deferred();this._lastUserId!=f&&(this._lastUserId=f,d.render("mod_assign/loading",{}).done(function(e,h){if(this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,e,h),this._region.fadeIn("fast")}.bind(this)),f<0)return void d.render("mod_assign/grading_navigation_no_users",{}).done(function(a,b){this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception);if("undefined"!=typeof this._userCache[f])g.resolve(this._userCache[f]);else{var i=this._getAssignmentId(),j=c.call([{methodname:"mod_assign_get_participant",args:{userid:f,assignid:i,embeduser:!0}}]);j[0].done(function(a){a.hasOwnProperty("id")?(this._userCache[f]=a,g.resolve(this._userCache[f])):g.reject("No users")}.bind(this)).fail(b.exception)}g.done(function(c){var e=a("[data-showuseridentity]").data("showuseridentity").split(","),f=[];c.courseid=a('[data-region="grading-navigation-panel"]').attr("data-courseid"),c.user&&(a.each(e,function(a,b){"undefined"!=typeof c.user[b]&&""!==c.user[b]&&(c.hasidentity=!0,f.push(c.user[b]))}),c.identity=f.join(", "),c.user.profileimageurl&&(c.profileimageurl=c.user.profileimageurl)),d.render("mod_assign/grading_navigation_user_summary",c).done(function(a,b){this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception)}.bind(this)).fail(function(){d.render("mod_assign/grading_navigation_no_users",{}).done(function(a,b){this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception)}.bind(this))}.bind(this)).fail(b.exception))},e});
|
||||
define(["jquery","core/notification","core/ajax","core/templates"],function(a,b,c,d){var e=function(b){this._regionSelector=b,this._region=a(b),this._userCache={},a(document).on("user-changed",this._refreshUserInfo.bind(this))};return e.prototype._regionSelector=null,e.prototype._userCache=null,e.prototype._region=null,e.prototype._lastUserId=0,e.prototype._getAssignmentId=function(){return this._region.attr("data-assignmentid")},e.prototype._refreshUserInfo=function(e,f){var g=a.Deferred();this._lastUserId!=f&&(this._lastUserId=f,d.render("mod_assign/loading",{}).done(function(e,h){if(this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,e,h),this._region.fadeIn("fast")}.bind(this)),f<0)return void d.render("mod_assign/grading_navigation_no_users",{}).done(function(a,b){f==this._lastUserId&&this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception);if("undefined"!=typeof this._userCache[f])g.resolve(this._userCache[f]);else{var i=this._getAssignmentId(),j=c.call([{methodname:"mod_assign_get_participant",args:{userid:f,assignid:i,embeduser:!0}}]);j[0].done(function(a){a.hasOwnProperty("id")?(this._userCache[f]=a,g.resolve(this._userCache[f])):g.reject("No users")}.bind(this)).fail(b.exception)}g.done(function(c){var e=a("[data-showuseridentity]").data("showuseridentity").split(","),g=[];c.courseid=a('[data-region="grading-navigation-panel"]').attr("data-courseid"),c.user&&(a.each(e,function(a,b){"undefined"!=typeof c.user[b]&&""!==c.user[b]&&(c.hasidentity=!0,g.push(c.user[b]))}),c.identity=g.join(", "),c.user.profileimageurl&&(c.profileimageurl=c.user.profileimageurl)),d.render("mod_assign/grading_navigation_user_summary",c).done(function(a,b){f==this._lastUserId&&this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception)}.bind(this)).fail(function(){d.render("mod_assign/grading_navigation_no_users",{}).done(function(a,b){this._region.fadeOut("fast",function(){d.replaceNodeContents(this._region,a,b),this._region.fadeIn("fast")}.bind(this))}.bind(this)).fail(b.exception)}.bind(this))}.bind(this)).fail(b.exception))},e});
|
@ -1 +1 @@
|
||||
define(["core/ajax","jquery","core/templates"],function(a,b,c){return{processResults:function(a,b){return b},transport:function(d,e,f,g){var h=b(d).attr("data-assignmentid"),i=b(d).attr("data-groupid"),j=b('[data-region="configure-filters"] input[type="checkbox"]'),k=[];j.each(function(a,c){k[b(c).attr("name")]=b(c).prop("checked")}),a.call([{methodname:"mod_assign_list_participants",args:{assignid:h,groupid:i,filter:e,limit:30,includeenrolments:!1}}])[0].then(function(a){var d=[],e=b("[data-showuseridentity]").data("showuseridentity").split(",");return b.each(a,function(a,f){var g=f,h=[],i=!0;k.filter_submitted&&!f.submitted&&(i=!1),k.filter_notsubmitted&&f.submitted&&(i=!1),k.filter_requiregrading&&!f.requiregrading&&(i=!1),k.filter_grantedextension&&!f.grantedextension&&(i=!1),i&&(b.each(e,function(a,b){"undefined"!=typeof f[b]&&""!==f[b]&&(g.hasidentity=!0,h.push(f[b]))}),g.identity=h.join(", "),d.push(c.render("mod_assign/list_participant_user_summary",g).then(function(a){return{value:f.id,label:a}})))}),b.when.apply(b,d)}).then(function(){var a=[];arguments[0]&&(a=Array.prototype.slice.call(arguments)),f(a)})["catch"](g)}}});
|
||||
define(["core/ajax","jquery","core/templates"],function(a,b,c){return{processResults:function(a,b){return b},transport:function(d,e,f,g){var h=b(d).attr("data-assignmentid"),i=b(d).attr("data-groupid"),j=b('[data-region="configure-filters"] input[type="checkbox"]'),k=[];j.each(function(a,c){k[b(c).attr("name")]=b(c).prop("checked")}),a.call([{methodname:"mod_assign_list_participants",args:{assignid:h,groupid:i,filter:e,limit:30,includeenrolments:!1,tablesort:!0}}])[0].then(function(a){var d=[],e=b("[data-showuseridentity]").data("showuseridentity").split(",");return b.each(a,function(a,f){var g=f,h=[],i=!0;k.filter_submitted&&!f.submitted&&(i=!1),k.filter_notsubmitted&&f.submitted&&(i=!1),k.filter_requiregrading&&!f.requiregrading&&(i=!1),k.filter_grantedextension&&!f.grantedextension&&(i=!1),i&&(b.each(e,function(a,b){"undefined"!=typeof f[b]&&""!==f[b]&&(g.hasidentity=!0,h.push(f[b]))}),g.identity=h.join(", "),d.push(c.render("mod_assign/list_participant_user_summary",g).then(function(a){return{value:f.id,label:a}})))}),b.when.apply(b,d)}).then(function(){var a=[];arguments[0]&&(a=Array.prototype.slice.call(arguments)),f(a)})["catch"](g)}}});
|
@ -38,10 +38,13 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
this._filters = [];
|
||||
this._users = [];
|
||||
this._filteredUsers = [];
|
||||
this._lastXofYUpdate = 0;
|
||||
this._firstLoadUsers = true;
|
||||
|
||||
// Get the current user list from a webservice.
|
||||
this._loadAllUsers();
|
||||
|
||||
// We do not allow navigation while ajax requests are pending.
|
||||
// Attach listeners to the select and arrow buttons.
|
||||
|
||||
this._region.find('[data-action="previous-user"]').on('click', this._handlePreviousUser.bind(this));
|
||||
@ -56,7 +59,7 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
var toggleLink = this._region.find('[data-region="user-filters"]');
|
||||
var configPanel = $(document.getElementById(toggleLink.attr('aria-controls')));
|
||||
|
||||
configPanel.on('change', '[type="checkbox"]', this._filterChanged.bind(this));
|
||||
configPanel.on('change', 'select', this._filterChanged.bind(this));
|
||||
|
||||
var userid = $('[data-region="grading-navigation-panel"]').data('first-userid');
|
||||
if (userid) {
|
||||
@ -68,8 +71,6 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
}
|
||||
).fail(notification.exception);
|
||||
|
||||
// We do not allow navigation while ajax requests are pending.
|
||||
|
||||
$(document).bind("start-loading-user", function() {
|
||||
this._isLoading = true;
|
||||
}.bind(this));
|
||||
@ -93,23 +94,44 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
/** @type {JQuery} JQuery node for the page region containing the user navigation. */
|
||||
GradingNavigation.prototype._region = null;
|
||||
|
||||
/** @type {String} Last active filters */
|
||||
GradingNavigation.prototype._lastFilters = '';
|
||||
|
||||
/**
|
||||
* Load the list of all users for this assignment.
|
||||
*
|
||||
* @private
|
||||
* @method _loadAllUsers
|
||||
* @return {Boolean} True if the user list was fetched.
|
||||
*/
|
||||
GradingNavigation.prototype._loadAllUsers = function() {
|
||||
var select = this._region.find('[data-action=change-user]');
|
||||
var assignmentid = select.attr('data-assignmentid');
|
||||
var groupid = select.attr('data-groupid');
|
||||
|
||||
var filterPanel = this._region.find('[data-region="configure-filters"]');
|
||||
var filter = filterPanel.find('select[name="filter"]').val();
|
||||
var workflowFilter = filterPanel.find('select[name="workflowfilter"]');
|
||||
if (workflowFilter) {
|
||||
filter += ',' + workflowFilter.val();
|
||||
}
|
||||
var markerFilter = filterPanel.find('select[name="markerfilter"]');
|
||||
if (markerFilter) {
|
||||
filter += ',' + markerFilter.val();
|
||||
}
|
||||
|
||||
if (this._lastFilters == filter) {
|
||||
return false;
|
||||
}
|
||||
this._lastFilters = filter;
|
||||
|
||||
ajax.call([{
|
||||
methodname: 'mod_assign_list_participants',
|
||||
args: {assignid: assignmentid, groupid: groupid, filter: '', onlyids: true},
|
||||
args: {assignid: assignmentid, groupid: groupid, filter: '', onlyids: true, tablesort: true},
|
||||
done: this._usersLoaded.bind(this),
|
||||
fail: notification.exception
|
||||
}]);
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -120,13 +142,14 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
* @param {Array} users
|
||||
*/
|
||||
GradingNavigation.prototype._usersLoaded = function(users) {
|
||||
this._firstLoadUsers = false;
|
||||
this._filteredUsers = this._users = users;
|
||||
if (this._users.length) {
|
||||
// Position the configure filters panel under the link that expands it.
|
||||
var toggleLink = this._region.find('[data-region="user-filters"]');
|
||||
var configPanel = $(document.getElementById(toggleLink.attr('aria-controls')));
|
||||
|
||||
configPanel.find('[type="checkbox"]').trigger('change');
|
||||
configPanel.find('select[name="filter"]').trigger('change');
|
||||
} else {
|
||||
this._selectNoUser();
|
||||
}
|
||||
@ -153,6 +176,48 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Close the configure filters panel if a click is detected outside of it.
|
||||
*
|
||||
* @private
|
||||
* @method _updateFilterPreference
|
||||
* @param {Number} userId The current user id.
|
||||
* @param {Array} filterList The list of current filter values.
|
||||
* @param {Array} preferenceNames The names of the preferences to update
|
||||
* @return {Promise} Resolved when all the preferences are updated.
|
||||
*/
|
||||
GradingNavigation.prototype._updateFilterPreferences = function(userId, filterList, preferenceNames) {
|
||||
var preferences = [],
|
||||
i = 0;
|
||||
|
||||
if (filterList.length == 0 || this._firstLoadUsers) {
|
||||
// Nothing to update.
|
||||
var deferred = $.Deferred();
|
||||
deferred.resolve();
|
||||
return deferred;
|
||||
}
|
||||
// General filter.
|
||||
// Set the user preferences to the current filters.
|
||||
for (i = 0; i < filterList.length; i++) {
|
||||
var newValue = filterList[i];
|
||||
if (newValue == 'none') {
|
||||
newValue = '';
|
||||
}
|
||||
|
||||
preferences.push({
|
||||
userid: userId,
|
||||
name: preferenceNames[i],
|
||||
value: newValue
|
||||
});
|
||||
}
|
||||
|
||||
return ajax.call([{
|
||||
methodname: 'core_user_set_user_preferences',
|
||||
args: {
|
||||
preferences: preferences
|
||||
}
|
||||
}])[0];
|
||||
};
|
||||
/**
|
||||
* Turn a filter on or off.
|
||||
*
|
||||
@ -160,28 +225,20 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
* @method _filterChanged
|
||||
* @param {Event} event
|
||||
*/
|
||||
GradingNavigation.prototype._filterChanged = function(event) {
|
||||
var name = $(event.target).attr('name');
|
||||
var key = name.split('_').pop();
|
||||
var enabled = $(event.target).prop('checked');
|
||||
GradingNavigation.prototype._filterChanged = function() {
|
||||
// There are 3 types of filter right now.
|
||||
var filterPanel = this._region.find('[data-region="configure-filters"]');
|
||||
var filters = filterPanel.find('select');
|
||||
|
||||
if (enabled) {
|
||||
if (this._filters.indexOf(key) == -1) {
|
||||
this._filters[this._filters.length] = key;
|
||||
}
|
||||
} else {
|
||||
var index = this._filters.indexOf(key);
|
||||
if (index != -1) {
|
||||
this._filters.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this._filters = [];
|
||||
filters.each(function(idx, ele) {
|
||||
this._filters.push($(ele).val());
|
||||
}.bind(this));
|
||||
|
||||
// Update the active filter string.
|
||||
var filterlist = [];
|
||||
this._region.find('[data-region="configure-filters"]').find('[type="checkbox"]').each(function(idx, ele) {
|
||||
if ($(ele).prop('checked')) {
|
||||
filterlist[filterlist.length] = $(ele).closest('label').text();
|
||||
}
|
||||
filterPanel.find('option:checked').each(function(idx, ele) {
|
||||
filterlist[filterlist.length] = $(ele).text();
|
||||
});
|
||||
if (filterlist.length) {
|
||||
this._region.find('[data-region="user-filters"] span').text(filterlist.join(', '));
|
||||
@ -191,50 +248,30 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
}.bind(this)).fail(notification.exception);
|
||||
}
|
||||
|
||||
// Filter the options in the select box that do not match the current filters.
|
||||
|
||||
var select = this._region.find('[data-action=change-user]');
|
||||
var userid = select.attr('data-selected');
|
||||
var foundIndex = 0;
|
||||
var currentUserID = select.data('currentuserid');
|
||||
var preferenceNames = ['assign_filter', 'assign_workflowfilter', 'assign_markerfilter'];
|
||||
this._updateFilterPreferences(currentUserID, this._filters, preferenceNames).done(function() {
|
||||
// Reload the list of users to apply the new filters.
|
||||
if (!this._loadAllUsers()) {
|
||||
var userid = parseInt(select.attr('data-selected'));
|
||||
var foundIndex = 0;
|
||||
// Search the returned users for the current selection.
|
||||
$.each(this._filteredUsers, function(index, user) {
|
||||
if (userid == user.id) {
|
||||
foundIndex = index;
|
||||
}
|
||||
});
|
||||
|
||||
this._filteredUsers = [];
|
||||
|
||||
$.each(this._users, function(index, user) {
|
||||
var show = true;
|
||||
$.each(this._filters, function(filterindex, filter) {
|
||||
if (filter == "submitted") {
|
||||
if (user.submitted == "0") {
|
||||
show = false;
|
||||
}
|
||||
} else if (filter == "notsubmitted") {
|
||||
if (user.submitted == "1") {
|
||||
show = false;
|
||||
}
|
||||
} else if (filter == "requiregrading") {
|
||||
if (user.requiregrading == "0") {
|
||||
show = false;
|
||||
}
|
||||
} else if (filter == "grantedextension") {
|
||||
if (user.grantedextension == "0") {
|
||||
show = false;
|
||||
}
|
||||
if (this._filteredUsers.length) {
|
||||
this._selectUserById(this._filteredUsers[foundIndex].id);
|
||||
} else {
|
||||
this._selectNoUser();
|
||||
}
|
||||
});
|
||||
|
||||
if (show) {
|
||||
this._filteredUsers[this._filteredUsers.length] = user;
|
||||
if (userid == user.id) {
|
||||
foundIndex = (this._filteredUsers.length - 1);
|
||||
}
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
if (this._filteredUsers.length) {
|
||||
this._selectUserById(this._filteredUsers[foundIndex].id);
|
||||
} else {
|
||||
this._selectNoUser();
|
||||
}
|
||||
this._triggerNextUserEvent();
|
||||
}.bind(this)).fail(notification.exception);
|
||||
this._refreshCount();
|
||||
};
|
||||
|
||||
/**
|
||||
@ -396,6 +433,28 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set count string. This method only sets the value for the last time it was ever called to deal
|
||||
* with promises that return in a non-predictable order.
|
||||
*
|
||||
* @private
|
||||
* @method _setCountString
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
GradingNavigation.prototype._setCountString = function(x, y) {
|
||||
var updateNumber = 0;
|
||||
this._lastXofYUpdate++;
|
||||
updateNumber = this._lastXofYUpdate;
|
||||
|
||||
var param = {x: x, y: y};
|
||||
str.get_string('xofy', 'mod_assign', param).done(function(s) {
|
||||
if (updateNumber == this._lastXofYUpdate) {
|
||||
this._region.find('[data-region="user-count-summary"]').text(s);
|
||||
}
|
||||
}.bind(this)).fail(notification.exception);
|
||||
};
|
||||
|
||||
/**
|
||||
* Rebuild the x of y string.
|
||||
*
|
||||
@ -423,11 +482,19 @@ define(['jquery', 'core/notification', 'core/str', 'core/form-autocomplete',
|
||||
if (count) {
|
||||
currentIndex += 1;
|
||||
}
|
||||
var param = {x: currentIndex, y: count};
|
||||
|
||||
str.get_string('xofy', 'mod_assign', param).done(function(s) {
|
||||
this._region.find('[data-region="user-count-summary"]').text(s);
|
||||
}.bind(this)).fail(notification.exception);
|
||||
this._setCountString(currentIndex, count);
|
||||
// Update window URL
|
||||
if (currentIndex > 0) {
|
||||
var url = new URL(window.location);
|
||||
if (parseInt(url.searchParams.get('blindid')) > 0) {
|
||||
var newid = this._filteredUsers[currentIndex - 1].recordid;
|
||||
url.searchParams.set('blindid', newid);
|
||||
} else {
|
||||
url.searchParams.set('userid', userid);
|
||||
}
|
||||
// We do this so a browser refresh will return to the same user.
|
||||
window.history.replaceState({}, "", url);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -48,7 +48,7 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates'], function(
|
||||
/** @type {JQuery} JQuery node for the page region containing the user navigation. */
|
||||
UserInfo.prototype._region = null;
|
||||
|
||||
/** @type {Integer} Remember the last user id to prevent unnessecary reloads. */
|
||||
/** @type {Integer} Remember the last user id to prevent unnecessary reloads. */
|
||||
UserInfo.prototype._lastUserId = 0;
|
||||
|
||||
/**
|
||||
@ -90,11 +90,13 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates'], function(
|
||||
if (userid < 0) {
|
||||
// Render the template.
|
||||
templates.render('mod_assign/grading_navigation_no_users', {}).done(function(html, js) {
|
||||
// Update the page.
|
||||
this._region.fadeOut("fast", function() {
|
||||
templates.replaceNodeContents(this._region, html, js);
|
||||
this._region.fadeIn("fast");
|
||||
}.bind(this));
|
||||
if (userid == this._lastUserId) {
|
||||
// Update the page.
|
||||
this._region.fadeOut("fast", function() {
|
||||
templates.replaceNodeContents(this._region, html, js);
|
||||
this._region.fadeIn("fast");
|
||||
}.bind(this));
|
||||
}
|
||||
}.bind(this)).fail(notification.exception);
|
||||
return;
|
||||
}
|
||||
@ -147,10 +149,12 @@ define(['jquery', 'core/notification', 'core/ajax', 'core/templates'], function(
|
||||
|
||||
templates.render('mod_assign/grading_navigation_user_summary', context).done(function(html, js) {
|
||||
// Update the page.
|
||||
this._region.fadeOut("fast", function() {
|
||||
templates.replaceNodeContents(this._region, html, js);
|
||||
this._region.fadeIn("fast");
|
||||
}.bind(this));
|
||||
if (userid == this._lastUserId) {
|
||||
this._region.fadeOut("fast", function() {
|
||||
templates.replaceNodeContents(this._region, html, js);
|
||||
this._region.fadeIn("fast");
|
||||
}.bind(this));
|
||||
}
|
||||
}.bind(this)).fail(notification.exception);
|
||||
}.bind(this)).fail(function() {
|
||||
// Render the template.
|
||||
|
@ -59,7 +59,14 @@ define(['core/ajax', 'jquery', 'core/templates'], function(ajax, $, templates) {
|
||||
|
||||
ajax.call([{
|
||||
methodname: 'mod_assign_list_participants',
|
||||
args: {assignid: assignmentid, groupid: groupid, filter: query, limit: 30, includeenrolments: false}
|
||||
args: {
|
||||
assignid: assignmentid,
|
||||
groupid: groupid,
|
||||
filter: query,
|
||||
limit: 30,
|
||||
includeenrolments: false,
|
||||
tablesort: true
|
||||
}
|
||||
}])[0].then(function(results) {
|
||||
var promises = [];
|
||||
var identityfields = $('[data-showuseridentity]').data('showuseridentity').split(',');
|
||||
|
@ -67,6 +67,9 @@ class grading_app implements templatable, renderable {
|
||||
$this->userid = $userid;
|
||||
$this->groupid = $groupid;
|
||||
$this->assignment = $assignment;
|
||||
user_preference_allow_ajax_update('assign_filter', PARAM_ALPHA);
|
||||
user_preference_allow_ajax_update('assign_workflowfilter', PARAM_ALPHA);
|
||||
user_preference_allow_ajax_update('assign_markerfilter', PARAM_ALPHANUMEXT);
|
||||
$this->participants = $assignment->list_participants_with_filter_status_and_group($groupid);
|
||||
if (!$this->userid && count($this->participants)) {
|
||||
$this->userid = reset($this->participants)->id;
|
||||
@ -80,7 +83,7 @@ class grading_app implements templatable, renderable {
|
||||
* @return stdClass - Flat list of exported data.
|
||||
*/
|
||||
public function export_for_template(renderer_base $output) {
|
||||
global $CFG;
|
||||
global $CFG, $USER;
|
||||
|
||||
$export = new stdClass();
|
||||
$export->userid = $this->userid;
|
||||
@ -91,6 +94,12 @@ class grading_app implements templatable, renderable {
|
||||
$export->name = $this->assignment->get_context()->get_context_name();
|
||||
$export->courseid = $this->assignment->get_course()->id;
|
||||
$export->participants = array();
|
||||
$export->filters = $this->assignment->get_filters();
|
||||
$export->markingworkflowfilters = $this->assignment->get_marking_workflow_filters(true);
|
||||
$export->hasmarkingworkflow = count($export->markingworkflowfilters) > 0;
|
||||
$export->markingallocationfilters = $this->assignment->get_marking_allocation_filters(true);
|
||||
$export->hasmarkingallocation = count($export->markingallocationfilters) > 0;
|
||||
|
||||
$num = 1;
|
||||
foreach ($this->participants as $idx => $record) {
|
||||
$user = new stdClass();
|
||||
@ -160,6 +169,7 @@ class grading_app implements templatable, renderable {
|
||||
$export->larrow = $output->larrow();
|
||||
// List of identity fields to display (the user info will not contain any fields the user cannot view anyway).
|
||||
$export->showuseridentity = $CFG->showuseridentity;
|
||||
$export->currentuserid = $USER->id;
|
||||
|
||||
return $export;
|
||||
}
|
||||
|
@ -2560,7 +2560,9 @@ class mod_assign_external extends external_api {
|
||||
'limit' => new external_value(PARAM_INT, 'maximum number of records to return', VALUE_DEFAULT, 0),
|
||||
'onlyids' => new external_value(PARAM_BOOL, 'Do not return all user fields', VALUE_DEFAULT, false),
|
||||
'includeenrolments' => new external_value(PARAM_BOOL, 'Do return courses where the user is enrolled',
|
||||
VALUE_DEFAULT, true)
|
||||
VALUE_DEFAULT, true),
|
||||
'tablesort' => new external_value(PARAM_BOOL, 'Apply current user table sorting preferences.',
|
||||
VALUE_DEFAULT, false)
|
||||
)
|
||||
);
|
||||
}
|
||||
@ -2575,11 +2577,13 @@ class mod_assign_external extends external_api {
|
||||
* @param int $limit Maximum number of records to return
|
||||
* @param bool $onlyids Only return user ids.
|
||||
* @param bool $includeenrolments Return courses where the user is enrolled.
|
||||
* @param bool $tablesort Apply current user table sorting params from the grading table.
|
||||
* @return array of warnings and status result
|
||||
* @since Moodle 3.1
|
||||
* @throws moodle_exception
|
||||
*/
|
||||
public static function list_participants($assignid, $groupid, $filter, $skip, $limit, $onlyids, $includeenrolments) {
|
||||
public static function list_participants($assignid, $groupid, $filter, $skip,
|
||||
$limit, $onlyids, $includeenrolments, $tablesort) {
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot . "/mod/assign/locallib.php");
|
||||
require_once($CFG->dirroot . "/user/lib.php");
|
||||
@ -2592,7 +2596,8 @@ class mod_assign_external extends external_api {
|
||||
'skip' => $skip,
|
||||
'limit' => $limit,
|
||||
'onlyids' => $onlyids,
|
||||
'includeenrolments' => $includeenrolments
|
||||
'includeenrolments' => $includeenrolments,
|
||||
'tablesort' => $tablesort
|
||||
));
|
||||
$warnings = array();
|
||||
|
||||
@ -2604,7 +2609,7 @@ class mod_assign_external extends external_api {
|
||||
|
||||
$participants = array();
|
||||
if (groups_group_visible($params['groupid'], $course, $cm)) {
|
||||
$participants = $assign->list_participants_with_filter_status_and_group($params['groupid']);
|
||||
$participants = $assign->list_participants_with_filter_status_and_group($params['groupid'], $params['tablesort']);
|
||||
}
|
||||
|
||||
$userfields = user_get_default_fields();
|
||||
@ -2658,6 +2663,11 @@ class mod_assign_external extends external_api {
|
||||
if (!empty($record->groupname)) {
|
||||
$userdetails['groupname'] = $record->groupname;
|
||||
}
|
||||
// Unique id is required for blind marking.
|
||||
$userdetails['recordid'] = -1;
|
||||
if (!empty($record->recordid)) {
|
||||
$userdetails['recordid'] = $record->recordid;
|
||||
}
|
||||
|
||||
$result[] = $userdetails;
|
||||
}
|
||||
@ -2689,6 +2699,7 @@ class mod_assign_external extends external_api {
|
||||
$userdesc->keys['profileimageurl']->required = VALUE_OPTIONAL;
|
||||
$userdesc->keys['email']->desc = 'Email address';
|
||||
$userdesc->keys['idnumber']->desc = 'The idnumber of the user';
|
||||
$userdesc->keys['recordid'] = new external_value(PARAM_INT, 'record id');
|
||||
|
||||
// Define other keys.
|
||||
$otherkeys = [
|
||||
|
@ -2052,3 +2052,29 @@ function mod_assign_core_calendar_event_timestart_updated(\calendar_event $event
|
||||
$event->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of all the user preferences used by mod_assign.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function mod_assign_user_preferences() {
|
||||
$preferences = array();
|
||||
$preferences['assign_filter'] = array(
|
||||
'type' => PARAM_ALPHA,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => ''
|
||||
);
|
||||
$preferences['assign_workflowfilter'] = array(
|
||||
'type' => PARAM_ALPHA,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => ''
|
||||
);
|
||||
$preferences['assign_markerfilter'] = array(
|
||||
'type' => PARAM_ALPHANUMEXT,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => ''
|
||||
);
|
||||
|
||||
return $preferences;
|
||||
}
|
||||
|
@ -33,11 +33,12 @@ define('ASSIGN_SUBMISSION_STATUS_DRAFT', 'draft');
|
||||
define('ASSIGN_SUBMISSION_STATUS_SUBMITTED', 'submitted');
|
||||
|
||||
// Search filters for grading page.
|
||||
define('ASSIGN_FILTER_NONE', 'none');
|
||||
define('ASSIGN_FILTER_SUBMITTED', 'submitted');
|
||||
define('ASSIGN_FILTER_NOT_SUBMITTED', 'notsubmitted');
|
||||
define('ASSIGN_FILTER_SINGLE_USER', 'singleuser');
|
||||
define('ASSIGN_FILTER_REQUIRE_GRADING', 'require_grading');
|
||||
define('ASSIGN_FILTER_GRANTED_EXTENSION', 'granted_extension');
|
||||
define('ASSIGN_FILTER_REQUIRE_GRADING', 'requiregrading');
|
||||
define('ASSIGN_FILTER_GRANTED_EXTENSION', 'grantedextension');
|
||||
|
||||
// Marker filter for grading page.
|
||||
define('ASSIGN_MARKER_FILTER_NO_MARKER', -1);
|
||||
@ -1954,11 +1955,12 @@ class assign {
|
||||
* If this is a group assignment, group info is also returned.
|
||||
*
|
||||
* @param int $currentgroup
|
||||
* @param boolean $tablesort Apply current user table sorting preferences.
|
||||
* @return array List of user records with extra fields 'submitted', 'notsubmitted', 'requiregrading', 'grantedextension',
|
||||
* 'groupid', 'groupname'
|
||||
*/
|
||||
public function list_participants_with_filter_status_and_group($currentgroup) {
|
||||
$participants = $this->list_participants($currentgroup, false);
|
||||
public function list_participants_with_filter_status_and_group($currentgroup, $tablesort = false) {
|
||||
$participants = $this->list_participants($currentgroup, false, $tablesort);
|
||||
|
||||
if (empty($participants)) {
|
||||
return $participants;
|
||||
@ -1967,17 +1969,56 @@ class assign {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a valid order by segment for list_participants that matches
|
||||
* the sorting of the current grading table. Not every field is supported,
|
||||
* we are only concerned with a list of users so we can't search on anything
|
||||
* that is not part of the user information (like grading statud or last modified stuff).
|
||||
*
|
||||
* @return string Order by clause for list_participants
|
||||
*/
|
||||
private function get_grading_sort_sql() {
|
||||
$usersort = flexible_table::get_sort_for_table('mod_assign_grading');
|
||||
$extrauserfields = get_extra_user_fields($this->get_context());
|
||||
|
||||
$userfields = explode(',', user_picture::fields('', $extrauserfields));
|
||||
$orderfields = explode(',', $usersort);
|
||||
$validlist = [];
|
||||
|
||||
foreach ($orderfields as $orderfield) {
|
||||
$orderfield = trim($orderfield);
|
||||
foreach ($userfields as $field) {
|
||||
$parts = explode(' ', $orderfield);
|
||||
if ($parts[0] == $field) {
|
||||
// Prepend the user table prefix and count this as a valid order field.
|
||||
array_push($validlist, 'u.' . $orderfield);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Produce a final list.
|
||||
$result = implode(',', $validlist);
|
||||
if (empty($result)) {
|
||||
// Fall back ordering when none has been set.
|
||||
$result = 'u.lastname, u.firstname, u.id';
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a list of users enrolled in the current course with the specified permission and group.
|
||||
* 0 for no group.
|
||||
* Apply any current sort filters from the grading table.
|
||||
*
|
||||
* @param int $currentgroup
|
||||
* @param bool $idsonly
|
||||
* @return array List of user records
|
||||
*/
|
||||
public function list_participants($currentgroup, $idsonly) {
|
||||
public function list_participants($currentgroup, $idsonly, $tablesort = false) {
|
||||
global $DB, $USER;
|
||||
|
||||
// Get the last known sort order for the grading table.
|
||||
|
||||
if (empty($currentgroup)) {
|
||||
$currentgroup = 0;
|
||||
}
|
||||
@ -1989,6 +2030,7 @@ class assign {
|
||||
|
||||
$fields = 'u.*';
|
||||
$orderby = 'u.lastname, u.firstname, u.id';
|
||||
|
||||
$additionaljoins = '';
|
||||
$additionalfilters = '';
|
||||
$instance = $this->get_instance();
|
||||
@ -2009,7 +2051,9 @@ class assign {
|
||||
// Note, different DBs have different ordering of NULL values.
|
||||
// Therefore we coalesce the current time into the timecreated field, and the max possible integer into
|
||||
// the ID field.
|
||||
$orderby = "COALESCE(s.timecreated, " . time() . ") ASC, COALESCE(s.id, " . PHP_INT_MAX . ") ASC, um.id ASC";
|
||||
if (empty($tablesort)) {
|
||||
$orderby = "COALESCE(s.timecreated, " . time() . ") ASC, COALESCE(s.id, " . PHP_INT_MAX . ") ASC, um.id ASC";
|
||||
}
|
||||
}
|
||||
|
||||
if ($instance->markingworkflow &&
|
||||
@ -2044,6 +2088,19 @@ class assign {
|
||||
$this->participants[$key] = $users;
|
||||
}
|
||||
|
||||
if ($tablesort) {
|
||||
// Resort the user list according to the grading table sort and filter settings.
|
||||
$sortedfiltereduserids = $this->get_grading_userid_list(true, '');
|
||||
$sortedfilteredusers = [];
|
||||
foreach ($sortedfiltereduserids as $nextid) {
|
||||
$nextid = intval($nextid);
|
||||
if (isset($this->participants[$key][$nextid])) {
|
||||
$sortedfilteredusers[$nextid] = $this->participants[$key][$nextid];
|
||||
}
|
||||
}
|
||||
$this->participants[$key] = $sortedfilteredusers;
|
||||
}
|
||||
|
||||
if ($idsonly) {
|
||||
$idslist = array();
|
||||
foreach ($this->participants[$key] as $id => $user) {
|
||||
@ -2338,9 +2395,21 @@ class assign {
|
||||
* Utility function to get the userid for every row in the grading table
|
||||
* so the order can be frozen while we iterate it.
|
||||
*
|
||||
* @param boolean $cached If true, the cached list from the session could be returned.
|
||||
* @param string $useridlistid String value used for caching the participant list.
|
||||
* @return array An array of userids
|
||||
*/
|
||||
protected function get_grading_userid_list() {
|
||||
protected function get_grading_userid_list($cached = false, $useridlistid = '') {
|
||||
if ($cached) {
|
||||
if (empty($useridlistid)) {
|
||||
$useridlistid = $this->get_useridlist_key_id();
|
||||
}
|
||||
$useridlistkey = $this->get_useridlist_key($useridlistid);
|
||||
if (empty($SESSION->mod_assign_useridlist[$useridlistkey])) {
|
||||
$SESSION->mod_assign_useridlist[$useridlistkey] = $this->get_grading_userid_list(false, '');
|
||||
}
|
||||
return $SESSION->mod_assign_useridlist[$useridlistkey];
|
||||
}
|
||||
$filter = get_user_preferences('assign_filter', '');
|
||||
$table = new assign_grading_table($this, 0, $filter, 0, false);
|
||||
|
||||
@ -3962,11 +4031,7 @@ class assign {
|
||||
$attemptnumber = optional_param('attemptnumber', -1, PARAM_INT);
|
||||
|
||||
if (!$userid) {
|
||||
$useridlistkey = $this->get_useridlist_key($useridlistid);
|
||||
if (empty($SESSION->mod_assign_useridlist[$useridlistkey])) {
|
||||
$SESSION->mod_assign_useridlist[$useridlistkey] = $this->get_grading_userid_list();
|
||||
}
|
||||
$useridlist = $SESSION->mod_assign_useridlist[$useridlistkey];
|
||||
$useridlist = $this->get_grading_userid_list(true, $useridlistid);
|
||||
} else {
|
||||
$rownum = 0;
|
||||
$useridlistid = 0;
|
||||
@ -4260,13 +4325,7 @@ class assign {
|
||||
|
||||
$markingworkflow = $this->get_instance()->markingworkflow;
|
||||
// Get marking states to show in form.
|
||||
$markingworkflowoptions = array();
|
||||
if ($markingworkflow) {
|
||||
$notmarked = get_string('markingworkflowstatenotmarked', 'assign');
|
||||
$markingworkflowoptions[''] = get_string('filternone', 'assign');
|
||||
$markingworkflowoptions[ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED] = $notmarked;
|
||||
$markingworkflowoptions = array_merge($markingworkflowoptions, $this->get_marking_workflow_states_for_current_user());
|
||||
}
|
||||
$markingworkflowoptions = $this->get_marking_workflow_filters();
|
||||
|
||||
// Print options for changing the filter and changing the number of results per page.
|
||||
$gradingoptionsformparams = array('cm'=>$cmid,
|
||||
@ -6818,13 +6877,7 @@ class assign {
|
||||
}
|
||||
|
||||
// Get marking states to show in form.
|
||||
$markingworkflowoptions = array();
|
||||
if ($this->get_instance()->markingworkflow) {
|
||||
$notmarked = get_string('markingworkflowstatenotmarked', 'assign');
|
||||
$markingworkflowoptions[''] = get_string('filternone', 'assign');
|
||||
$markingworkflowoptions[ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED] = $notmarked;
|
||||
$markingworkflowoptions = array_merge($markingworkflowoptions, $this->get_marking_workflow_states_for_current_user());
|
||||
}
|
||||
$markingworkflowoptions = $this->get_marking_workflow_filters();
|
||||
|
||||
$gradingoptionsparams = array('cm'=>$this->get_course_module()->id,
|
||||
'contextid'=>$this->context->id,
|
||||
@ -7316,11 +7369,7 @@ class assign {
|
||||
$bothids = ($userid && $useridlistid);
|
||||
|
||||
if (!$userid || $bothids) {
|
||||
$useridlistkey = $this->get_useridlist_key($useridlistid);
|
||||
if (empty($SESSION->mod_assign_useridlist[$useridlistkey])) {
|
||||
$SESSION->mod_assign_useridlist[$useridlistkey] = $this->get_grading_userid_list();
|
||||
}
|
||||
$useridlist = $SESSION->mod_assign_useridlist[$useridlistkey];
|
||||
$useridlist = $this->get_grading_userid_list(true, $useridlistid);
|
||||
} else {
|
||||
$useridlist = array($userid);
|
||||
$rownum = 0;
|
||||
@ -8908,6 +8957,108 @@ class assign {
|
||||
public function set_most_recent_team_submission($submission) {
|
||||
$this->mostrecentteamsubmission = $submission;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of valid grading allocation filters for the grading interface.
|
||||
*
|
||||
* @param boolean $export Export the list of filters for a template.
|
||||
* @return array
|
||||
*/
|
||||
public function get_marking_allocation_filters($export = false) {
|
||||
$markingallocation = $this->get_instance()->markingworkflow &&
|
||||
$this->get_instance()->markingallocation &&
|
||||
has_capability('mod/assign:manageallocations', $this->context);
|
||||
// Get markers to use in drop lists.
|
||||
$markingallocationoptions = array();
|
||||
if ($markingallocation) {
|
||||
list($sort, $params) = users_order_by_sql('u');
|
||||
// Only enrolled users could be assigned as potential markers.
|
||||
$markers = get_enrolled_users($this->context, 'mod/assign:grade', 0, 'u.*', $sort);
|
||||
$markingallocationoptions[''] = get_string('filternone', 'assign');
|
||||
$markingallocationoptions[ASSIGN_MARKER_FILTER_NO_MARKER] = get_string('markerfilternomarker', 'assign');
|
||||
$viewfullnames = has_capability('moodle/site:viewfullnames', $this->context);
|
||||
foreach ($markers as $marker) {
|
||||
$markingallocationoptions[$marker->id] = fullname($marker, $viewfullnames);
|
||||
}
|
||||
}
|
||||
if ($export) {
|
||||
$allocationfilter = get_user_preferences('assign_markerfilter', '');
|
||||
$result = [];
|
||||
foreach ($markingallocationoptions as $option => $label) {
|
||||
array_push($result, [
|
||||
'key' => $option,
|
||||
'name' => $label,
|
||||
'active' => ($allocationfilter == $option),
|
||||
]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $markingworkflowoptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of valid grading workflow filters for the grading interface.
|
||||
*
|
||||
* @param boolean $export Export the list of filters for a template.
|
||||
* @return array
|
||||
*/
|
||||
public function get_marking_workflow_filters($export = false) {
|
||||
$markingworkflow = $this->get_instance()->markingworkflow;
|
||||
// Get marking states to show in form.
|
||||
$markingworkflowoptions = array();
|
||||
if ($markingworkflow) {
|
||||
$notmarked = get_string('markingworkflowstatenotmarked', 'assign');
|
||||
$markingworkflowoptions[''] = get_string('filternone', 'assign');
|
||||
$markingworkflowoptions[ASSIGN_MARKING_WORKFLOW_STATE_NOTMARKED] = $notmarked;
|
||||
$markingworkflowoptions = array_merge($markingworkflowoptions, $this->get_marking_workflow_states_for_current_user());
|
||||
}
|
||||
if ($export) {
|
||||
$workflowfilter = get_user_preferences('assign_workflowfilter', '');
|
||||
$result = [];
|
||||
foreach ($markingworkflowoptions as $option => $label) {
|
||||
array_push($result, [
|
||||
'key' => $option,
|
||||
'name' => $label,
|
||||
'active' => ($workflowfilter == $option),
|
||||
]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $markingworkflowoptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return array of valid search filters for the grading interface.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_filters() {
|
||||
$filterkeys = [
|
||||
ASSIGN_FILTER_SUBMITTED,
|
||||
ASSIGN_FILTER_NOT_SUBMITTED,
|
||||
ASSIGN_FILTER_REQUIRE_GRADING,
|
||||
ASSIGN_FILTER_GRANTED_EXTENSION
|
||||
];
|
||||
|
||||
$current = get_user_preferences('assign_filter', '');
|
||||
|
||||
$filters = [];
|
||||
// First is always "no filter" option.
|
||||
array_push($filters, [
|
||||
'key' => 'none',
|
||||
'name' => get_string('filternone', 'assign'),
|
||||
'active' => ($current == '')
|
||||
]);
|
||||
|
||||
foreach ($filterkeys as $key) {
|
||||
array_push($filters, [
|
||||
'key' => $key,
|
||||
'name' => get_string('filter' . $key, 'assign'),
|
||||
'active' => ($current == $key)
|
||||
]);
|
||||
}
|
||||
return $filters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,14 +354,14 @@
|
||||
.path-mod-assign [data-region="configure-filters"] {
|
||||
display: none;
|
||||
text-align: left;
|
||||
width: auto;
|
||||
width: 480px;
|
||||
background-color: #fff;
|
||||
background-clip: padding-box;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
margin-top: 28px;
|
||||
margin-left: -140px;
|
||||
margin-left: -452px;
|
||||
padding: 10px 0;
|
||||
z-index: 1;
|
||||
}
|
||||
@ -391,11 +391,6 @@
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
|
||||
.path-mod-assign [data-region="configure-filters"] label {
|
||||
display: block;
|
||||
padding: 3px 20px;
|
||||
}
|
||||
|
||||
.path-mod-assign .alignment [data-region="configure-filters"] input {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* data-action, data-assignmentid, data-groupid, data-region
|
||||
* data-action, data-assignmentid, data-groupid, data-region, data-currentuserid
|
||||
|
||||
Context variables required for this template:
|
||||
* see mod/assign/classes/output/grading_app.php
|
||||
@ -31,37 +31,73 @@
|
||||
This template uses ajax functionality, so it cannot be shown in the template library.
|
||||
}}
|
||||
<a href="#previous" data-action="previous-user">{{{larrow}}}</a>
|
||||
<span>
|
||||
<select data-action="change-user" data-assignmentid="{{assignmentid}}" data-groupid="{{groupid}}">
|
||||
</select>
|
||||
</span>
|
||||
<a href="#next" data-action="next-user">{{{rarrow}}}</a>
|
||||
<span>
|
||||
<select data-action="change-user" data-currentuserid="{{currentuserid}}" data-assignmentid="{{assignmentid}}" data-groupid="{{groupid}}">
|
||||
</select>
|
||||
</span>
|
||||
<a href="#next" data-action="next-user">{{{rarrow}}}</a>
|
||||
|
||||
<br>
|
||||
|
||||
<span data-region="user-count">
|
||||
<small>
|
||||
<span data-region="user-count-summary">{{#str}}xofy, mod_assign, { "x": "{{index}}", "y": "{{count}}" }{{/str}}</span>
|
||||
</small>
|
||||
<small>
|
||||
<span data-region="user-count-summary">{{#str}}xofy, mod_assign, { "x": "{{index}}", "y": "{{count}}" }{{/str}}</span>
|
||||
</small>
|
||||
</span>
|
||||
|
||||
<span data-region="configure-filters" id="filter-configuration-{{uniqid}}" class="well well-small">
|
||||
<form>
|
||||
<label><input type="checkbox" name="filter_submitted">{{#str}}filtersubmitted, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_notsubmitted">{{#str}}filternotsubmitted, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_requiregrading">{{#str}}filterrequiregrading, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_grantedextension">{{#str}}filtergrantedextension, mod_assign{{/str}}</label>
|
||||
</form>
|
||||
<span data-region="configure-filters" id="filter-configuration-{{uniqid}}" class="well well-large p-2">
|
||||
<form class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<label class="span4 text-right" for="filter-general-{{uniqid}}">
|
||||
{{#str}}filter, mod_assign{{/str}}
|
||||
</label>
|
||||
<div class="span8">
|
||||
<select name="filter" class="custom-select span8" id="filter-general-{{uniqid}}">
|
||||
{{#filters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}}> {{name}} </option>
|
||||
{{/filters}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{#hasmarkingallocation}}
|
||||
<div class="row-fluid">
|
||||
<label class="span4 text-right" for="filter-marker-{{uniqid}}">
|
||||
{{#str}}markerfilter, mod_assign{{/str}}
|
||||
</label>
|
||||
<div class="span8">
|
||||
<select name="markerfilter" class="custom-select span8" id="filter-marker-{{uniqid}}">
|
||||
{{#markingallocationfilters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}} > {{name}} </option>
|
||||
{{/markingallocationfilters}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/hasmarkingallocation}}
|
||||
{{#hasmarkingworkflow}}
|
||||
<div class="row-fluid">
|
||||
<label class="span4 text-right" for="filter-workflow-{{uniqid}}">
|
||||
{{#str}}workflowfilter, mod_assign{{/str}}
|
||||
</label>
|
||||
<div class="span8">
|
||||
<select name="workflowfilter" class="custom-select span8" id="filter-workflow-{{uniqid}}">
|
||||
{{#markingworkflowfilters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}} > {{name}} </option>
|
||||
{{/markingworkflowfilters}}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{{/hasmarkingworkflow}}
|
||||
</form>
|
||||
</span>
|
||||
|
||||
<a href="#" data-region="user-filters" title="{{#str}}changefilters, mod_assign{{/str}}" aria-expanded="false" aria-controls="filter-configuration-{{uniqid}}">
|
||||
<span class="accesshide">
|
||||
{{#filters}}
|
||||
{{filtername}}
|
||||
{{/filters}}
|
||||
{{^filters}}
|
||||
{{#str}}nofilters, mod_assign{{/str}}
|
||||
{{/filters}}
|
||||
</span>
|
||||
{{#pix}}i/filter{{/pix}}
|
||||
<span class="accesshide">
|
||||
{{#filters}}
|
||||
{{filtername}}
|
||||
{{/filters}}
|
||||
{{^filters}}
|
||||
{{#str}}nofilters, mod_assign{{/str}}
|
||||
{{/filters}}
|
||||
</span>
|
||||
{{#pix}}i/filter{{/pix}}
|
||||
</a>
|
||||
|
@ -12,10 +12,12 @@ Feature: View the grading status of an assignment
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
| student2 | Student | 2 | student2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario: View the grading status for an assignment with marking workflow enabled
|
||||
@ -46,6 +48,10 @@ Feature: View the grading status of an assignment
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I should see "Not marked" in the "Student 1" "table_row"
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "1 of 2"
|
||||
And I click on "Change filters" "link"
|
||||
And I set the field "Filter" to "submitted"
|
||||
And I should see "1 of 1"
|
||||
And I set the field "Grade out of 100" to "50"
|
||||
And I set the field "Marking workflow state" to "In review"
|
||||
And I set the field "Feedback comments" to "Great job! Lol, not really."
|
||||
@ -71,6 +77,7 @@ Feature: View the grading status of an assignment
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I should see "In review" in the "Student 1" "table_row"
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "1 of 1"
|
||||
And I set the field "Marking workflow state" to "Released"
|
||||
And I press "Save changes"
|
||||
And I press "Ok"
|
||||
@ -93,6 +100,7 @@ Feature: View the grading status of an assignment
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I should see "Released" in the "Student 1" "table_row"
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "1 of 1"
|
||||
And I set the field "Marking workflow state" to "In marking"
|
||||
And I set the field "Notify students" to "0"
|
||||
And I press "Save changes"
|
||||
@ -104,6 +112,11 @@ Feature: View the grading status of an assignment
|
||||
# The grade should also remain displayed as it's stored in the assign DB tables, but the final grade should be empty.
|
||||
And "Student 1" row "Grade" column of "generaltable" table should contain "50.00"
|
||||
And "Student 1" row "Final grade" column of "generaltable" table should contain "-"
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I click on "Change filters" "link"
|
||||
And I set the field "Workflow filter" to "In review"
|
||||
And I should see "0 of 0"
|
||||
And I follow "Test assignment name"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
@ -134,6 +147,10 @@ Feature: View the grading status of an assignment
|
||||
And I navigate to "View all submissions" in current page administration
|
||||
And I should not see "Graded" in the "Student 1" "table_row"
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "1 of 2"
|
||||
And I click on "Change filters" "link"
|
||||
And I set the field "Filter" to "submitted"
|
||||
And I should see "1 of 1"
|
||||
And I set the field "Grade out of 100" to "50"
|
||||
And I set the field "Feedback comments" to "Great job! Lol, not really."
|
||||
And I press "Save changes"
|
||||
@ -167,6 +184,7 @@ Feature: View the grading status of an assignment
|
||||
And I should see "Graded - follow up submission received" in the "Student 1" "table_row"
|
||||
And I wait "10" seconds
|
||||
And I click on "Grade" "link" in the "Student 1" "table_row"
|
||||
And I should see "1 of 1"
|
||||
And I set the field "Grade out of 100" to "99.99"
|
||||
And I set the field "Feedback comments" to "Even better job! Really."
|
||||
And I press "Save changes"
|
||||
|
@ -2425,7 +2425,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
|
||||
$DB->update_record('user', $student);
|
||||
|
||||
$this->setUser($teacher);
|
||||
$participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, true);
|
||||
$participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, true, true);
|
||||
$participants = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants);
|
||||
$this->assertCount(1, $participants);
|
||||
|
||||
@ -2443,7 +2443,7 @@ class mod_assign_external_testcase extends externallib_advanced_testcase {
|
||||
$this->assertEquals($student->institution, $participant['institution']);
|
||||
$this->assertArrayHasKey('enrolledcourses', $participant);
|
||||
|
||||
$participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, false);
|
||||
$participants = mod_assign_external::list_participants($assignment->id, 0, '', 0, 0, false, false, true);
|
||||
$participants = external_api::clean_returnvalue(mod_assign_external::list_participants_returns(), $participants);
|
||||
// Check that the list of courses the participant is enrolled is not returned.
|
||||
$participant = $participants[0];
|
||||
|
@ -3987,4 +3987,17 @@ Anchor link 2:<a title=\"bananas\" href=\"../logo-240x60.gif\">Link text</a>
|
||||
// Check that submissionstatus_marked 'Graded' message does appear for student.
|
||||
$this->assertContains(get_string('submissionstatus_marked', 'assign'), $output2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the result of get_filters is consistent.
|
||||
*/
|
||||
public function test_get_filters() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$assign = $this->create_instance($course);
|
||||
$valid = $assign->get_filters();
|
||||
|
||||
$this->assertEquals(count($valid), 5);
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
}}
|
||||
<a href="#previous" data-action="previous-user">{{{larrow}}}</a>
|
||||
<span data-region="input-field">
|
||||
<select data-action="change-user" data-assignmentid="{{assignmentid}}" data-groupid="{{groupid}}"></select>
|
||||
<select data-action="change-user" data-currentuserid="{{currentuserid}}" data-assignmentid="{{assignmentid}}" data-groupid="{{groupid}}"></select>
|
||||
</span>
|
||||
<a href="#next" data-action="next-user">{{{rarrow}}}</a>
|
||||
|
||||
@ -44,12 +44,42 @@
|
||||
</small>
|
||||
</span>
|
||||
|
||||
<span data-region="configure-filters" id="filter-configuration-{{uniqid}}" class="card card-small">
|
||||
<span data-region="configure-filters" id="filter-configuration-{{uniqid}}" class="card card-large p-2">
|
||||
<form>
|
||||
<label><input type="checkbox" name="filter_submitted">{{#str}}filtersubmitted, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_notsubmitted">{{#str}}filternotsubmitted, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_requiregrading">{{#str}}filterrequiregrading, mod_assign{{/str}}</label>
|
||||
<label><input type="checkbox" name="filter_grantedextension">{{#str}}filtergrantedextension, mod_assign{{/str}}</label>
|
||||
<span class="row px-3 py-1">
|
||||
<label class="text-right w-25 p-2 m-0" for="filter-general-{{uniqid}}">
|
||||
{{#str}}filter, mod_assign{{/str}}
|
||||
</label>
|
||||
<select name="filter" class="custom-select w-50" id="filter-general-{{uniqid}}">
|
||||
{{#filters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}} > {{name}} </option>
|
||||
{{/filters}}
|
||||
</select>
|
||||
</span>
|
||||
{{#hasmarkingallocation}}
|
||||
<span class="row px-3 py-1">
|
||||
<label class="text-right w-25 p-2 m-0" for="filter-marker-{{uniqid}}">
|
||||
{{#str}}markerfilter, mod_assign{{/str}}
|
||||
</label>
|
||||
<select name="markerfilter" class="custom-select w-50" id="filter-marker-{{uniqid}}">
|
||||
{{#markingallocationfilters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}} > {{name}} </option>
|
||||
{{/markingallocationfilters}}
|
||||
</select>
|
||||
</span>
|
||||
{{/hasmarkingallocation}}
|
||||
{{#hasmarkingworkflow}}
|
||||
<span class="row px-3 py-1">
|
||||
<label class="text-right w-25 p-2 m-0" for="filter-workflow-{{uniqid}}">
|
||||
{{#str}}workflowfilter, mod_assign{{/str}}
|
||||
</label>
|
||||
<select name="workflowfilter" class="custom-select w-50" id="filter-workflow-{{uniqid}}">
|
||||
{{#markingworkflowfilters}}
|
||||
<option value="{{key}}" {{#active}}selected="selected"{{/active}} > {{name}} </option>
|
||||
{{/markingworkflowfilters}}
|
||||
</select>
|
||||
</span>
|
||||
{{/hasmarkingworkflow}}
|
||||
</form>
|
||||
</span>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user