Merge branch 'MDL-66893-master-3' of https://github.com/ryanwyllie/moodle

This commit is contained in:
Jun Pataleta 2019-11-08 11:59:44 +08:00
commit 2e809ec27c
68 changed files with 2695 additions and 692 deletions

View File

@ -61,19 +61,35 @@
<form id="gradingform_guide-{{uniqid}}">
<input type="hidden" name="instanceid" value="{{instanceid}}">
{{#criterion}}
<div data-gradingform-guide-role="criterion">
<h5>
{{name}}
<a
href="#gradingform_guide-{{uniqid}}-criteria-{{id}}-description"
aria-controls="gradingform_guide-{{uniqid}}-criteria-{{id}}-description"
aria-expanded="false"
data-toggle="collapse"
role="button"
<div class="mb-3 criterion" data-gradingform-guide-role="criterion">
<div class="d-flex align-items-center">
<h5 class="description font-weight-bold mb-0">{{name}}</h5>
<button
class="btn btn-link px-1"
aria-controls="gradingform_guide-{{uniqid}}-criteria-{{id}}-description"
aria-expanded="false"
data-target="#gradingform_guide-{{uniqid}}-criteria-{{id}}-description"
data-toggle="collapse"
type="button"
>
{{# pix }} info, gradingform_guide {{/ pix }}
</a>
</h5>
</button>
<button class="criterion-toggle btn btn-icon icon-no-margin text-reset p-0 font-weight-bold mb-0 ml-auto"
type="button"
data-toggle="collapse"
data-target="#criteria-{{id}}"
aria-expanded="true"
aria-controls="criteria-{{id}}">
<span class="collapsed-icon">
{{#pix}} t/collapsed, core {{/pix}}
<span class="sr-only">{{#str}} expandcriterion, core_grades {{/str}}</span>
</span>
<span class="expanded-icon">
{{#pix}} t/expanded, core {{/pix}}
<span class="sr-only">{{#str}} collapsecriterion, core_grades {{/str}}</span>
</span>
</button>
</div>
<div class="collapse" id="gradingform_guide-{{uniqid}}-criteria-{{id}}-description">
<div class="border p-3 mb-3 bg-white rounded">
{{{description}}}
@ -83,52 +99,59 @@
{{/descriptionmarkers}}
</div>
</div>
<div class="form-group">
<label for="gradingform_guide-{{uniqid}}-criteria-{{id}}-score">{{#str}}outof, gradingform_guide, {{maxscore}}{{/str}}</label>
<input class="form-control" type="number" name="advancedgrading[criteria][{{id}}][score]" value="{{score}}"
id="gradingform_guide-{{uniqid}}-criteria-{{id}}-score"
aria-describedby="gradingform_guide-{{uniqid}}-help-{{id}}-score">
<small id="gradingform_guide-{{uniqid}}-help-{{id}}-score" class="sr-only">{{#str}}grade_help, gradingform_guide{{/str}}</small>
</div>
<div class="form-group ">
<label for="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark">{{#str}}additionalcomments, gradingform_guide{{/str}}</label>
<div class="input-group mb-3 form-inset form-inset-right">
<textarea class="form-control" type="text" name="advancedgrading[criteria][{{id}}][remark]"
id="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark"
aria-describedby="gradingform_guide-{{uniqid}}-help-{{id}}-remark"
data-gradingform-guide-role="remark"
>{{remark}}</textarea>
{{#hascomments}}
<a
class="form-inset-item"
href="#gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments"
aria-controls="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments"
aria-expanded="false"
data-toggle="collapse"
role="button"
>
{{#pix}}plus, gradingform_guide{{/pix}}
</a>
{{/hascomments}}
<div class="collapse show" id="criteria-{{id}}">
<div class="form-group">
<label for="gradingform_guide-{{uniqid}}-criteria-{{id}}-score">{{#str}}outof, gradingform_guide, {{maxscore}}{{/str}}</label>
<input class="form-control" type="number" name="advancedgrading[criteria][{{id}}][score]" value="{{score}}"
id="gradingform_guide-{{uniqid}}-criteria-{{id}}-score"
aria-describedby="gradingform_guide-{{uniqid}}-help-{{id}}-score">
<small id="gradingform_guide-{{uniqid}}-help-{{id}}-score" class="sr-only">{{#str}}grade_help, gradingform_guide{{/str}}</small>
</div>
{{#hascomments}}
<div class="collapse" id="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments">
<div data-gradingform_guide-frequent-comments="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark">
<div class="list-group">
{{#comments}}
<button type="button" class="list-group-item list-group-item-action" data-gradingform_guide-role="frequent-comment">{{description}}</button>
{{/comments}}
<div class="form-group ">
<label class="text-muted" for="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark">{{#str}}additionalcomments, gradingform_guide{{/str}}</label>
<div class="input-group mb-3 form-inset form-inset-right">
<textarea class="form-control" type="text" name="advancedgrading[criteria][{{id}}][remark]"
id="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark"
aria-describedby="gradingform_guide-{{uniqid}}-help-{{id}}-remark"
data-gradingform-guide-role="remark"
rows="2"
data-max-rows="5"
data-auto-rows
>{{remark}}</textarea>
{{#hascomments}}
<button
class="btn btn-icon form-inset-item icon-no-margin p-0 mt-1 mr-1 text-reset collapsed"
aria-controls="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments"
aria-expanded="false"
data-toggle="collapse"
data-target="#gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments"
type="button"
>
{{#pix}}plus, gradingform_guide{{/pix}}
</button>
{{/hascomments}}
</div>
{{#hascomments}}
<div class="collapse" id="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark-frequent-comments">
<div data-gradingform_guide-frequent-comments="gradingform_guide-{{uniqid}}-criteria-{{id}}-remark">
<h6>{{#str}}comments, gradingform_guide{{/str}}</h6>
<div class="list-group">
{{#comments}}
<button type="button" class="list-group-item list-group-item-action" data-gradingform_guide-role="frequent-comment">{{description}}</button>
{{/comments}}
</div>
</div>
</div>
</div>
{{/hascomments}}
<small id="gradingform_guide-{{uniqid}}-help-{{id}}-remark" class="sr-only">{{#str}}grade_help, gradingform_guide{{/str}}</small>
{{/hascomments}}
<small id="gradingform_guide-{{uniqid}}-help-{{id}}-remark" class="sr-only">{{#str}}grade_help, gradingform_guide{{/str}}</small>
</div>
</div>
</div>
{{/criterion}}
</form>
{{#js}}
require(['gradingform_guide/grades/grader/gradingpanel/comments'], function(Comments) {
require(['gradingform_guide/grades/grader/gradingpanel/comments', 'core/auto_rows'], function(Comments, AutoRows) {
Comments.init('gradingform_guide-{{uniqid}}');
AutoRows.init(document.getElementById('gradingform_guide-{{uniqid}}'));
});
{{/js}}

View File

@ -57,49 +57,71 @@
<input type="hidden" name="instanceid" value="{{instanceid}}">
<div id="rubric-advancedgrading-{{uniqid}}" class="criterion">
{{#criteria}}
<div class="d-block mb-2">
<h5 class="d-inline px-0 font-weight-bold mb-0">{{{description}}}</h5>
<button class="d-inline btn p-0 font-weight-bold mb-0 pull-right collapse"
type="button"
data-toggle="collapse"
data-target="#criteria-{{id}}"
aria-expanded="true"
aria-controls="criteria-{{id}}">
</button>
</div>
<div class="collapse show" id="criteria-{{id}}">
{{#levels}}
<div class="form-check">
<input class="form-check-input level"
type="radio"
name="advancedgrading[criteria][{{criterionid}}][levelid]"
id="advancedgrading-criteria-{{criterionid}}-levels-{{id}}-definition"
value="{{id}}"
{{#checked}}
aria-checked="true"
tabindex="0"
checked
{{/checked}}
{{^checked}}
aria-checked="false"
tabindex="-1"
{{/checked}}
>
<label class="w-100" for="advancedgrading-criteria-{{criterionid}}-levels-{{id}}-definition">
<label class="font-weight-bold">
{{{definition}}}
<div class="mb-3">
<div class="d-flex align-items-center mb-2">
<h5 class="px-0 mb-0 description font-weight-bold">{{{description}}}</h5>
<button class="criterion-toggle btn btn-icon icon-no-margin text-reset p-0 font-weight-bold mb-0 ml-auto"
type="button"
data-toggle="collapse"
data-target="#criteria-{{id}}"
aria-expanded="true"
aria-controls="criteria-{{id}}">
<span class="collapsed-icon">
{{#pix}} t/collapsed, core {{/pix}}
<span class="sr-only">{{#str}} expandcriterion, core_grades {{/str}}</span>
</span>
<span class="expanded-icon">
{{#pix}} t/expanded, core {{/pix}}
<span class="sr-only">{{#str}} collapsecriterion, core_grades {{/str}}</span>
</span>
</button>
</div>
<div class="collapse show" id="criteria-{{id}}">
{{#levels}}
<div class="form-check">
<input class="form-check-input level"
type="radio"
name="advancedgrading[criteria][{{criterionid}}][levelid]"
id="advancedgrading-criteria-{{criterionid}}-levels-{{id}}-definition"
value="{{id}}"
{{#checked}}
aria-checked="true"
tabindex="0"
checked
{{/checked}}
{{^checked}}
aria-checked="false"
tabindex="-1"
{{/checked}}
>
<label class="w-100" for="advancedgrading-criteria-{{criterionid}}-levels-{{id}}-definition">
<span>
{{{definition}}}
</span>
<span class="pull-right">
{{#str}}pointsvalue, gradingform_rubric, {{score}}{{/str}}
</span>
</label>
<label class="pull-right font-weight-bold">
{{#str}}pointsvalue, gradingform_rubric, {{score}}{{/str}}
</label>
</label>
</div>
{{/levels}}
<div class="form-group">
<label class="text-muted" for="advancedgrading-criteria-{{id}}-remark">{{#str}} additionalfeedback, core_grades {{/str}}</label>
<textarea class="form-control"
name="advancedgrading[criteria][{{id}}][remark]"
id="advancedgrading-criteria-{{id}}-remark"
cols="10"
rows="1"
data-max-rows="5"
data-auto-rows="true"
>{{{remark}}}</textarea>
</div>
{{/levels}}
<div class="form-group">
<label for="advancedgrading-criteria-{{id}}-remark">Additional feedback</label>
<textarea class="form-control" name="advancedgrading[criteria][{{id}}][remark]" id="advancedgrading-criteria-{{id}}-remark" cols="10" rows="5">{{{remark}}}</textarea>
</div>
</div>
{{/criteria}}
</div>
</form>
{{#js}}
require(['core/auto_rows'], function(AutoRows) {
AutoRows.init(document.getElementById('gradingform_rubric-{{uniqid}}'));
});
{{/js}}

View File

@ -30,6 +30,7 @@ $string['addfeedback'] = 'Add feedback';
$string['addgradeletter'] = 'Add a grade letter';
$string['addidnumbers'] = 'Add ID numbers';
$string['additem'] = 'Add grade item';
$string['additionalfeedback'] = 'Additional feedback';
$string['addoutcome'] = 'Add an outcome';
$string['addoutcomeitem'] = 'Add outcome item';
$string['addscale'] = 'Add a scale';
@ -118,6 +119,7 @@ $string['categoryname'] = 'Category name';
$string['categorytotal'] = 'Category total';
$string['categorytotalname'] = 'Category total name';
$string['categorytotalfull'] = '{$a->category} total';
$string['collapsecriterion'] = 'Collapse criterion';
$string['combo'] = 'Tabs and drop-down menu';
$string['compact'] = 'Compact';
$string['componentcontrolsvisibility'] = 'Whether this grade item is hidden is controlled by the activity settings.';
@ -207,6 +209,7 @@ $string['eventusergraded'] = 'User graded';
$string['excluded'] = 'Excluded';
$string['excluded_help'] = 'If ticked, the grade will not be included in any aggregation.';
$string['expand'] = 'Expand category';
$string['expandcriterion'] = 'Expand criterion';
$string['export'] = 'Export';
$string['exportalloutcomes'] = 'Export all outcomes';
$string['exportfeedback'] = 'Include feedback in export';
@ -354,6 +357,7 @@ $string['gradevaluetoobig'] = 'One of the grade values is larger than the allowe
$string['gradeview'] = 'View grade';
$string['gradewasmodifiedduringediting'] = 'The grade entered for {$a->itemname} for {$a->username} was ignored because it was more recently updated by someone else.';
$string['gradeweighthelp'] = 'Grade weight help';
$string['gradingmodulename'] = 'Grading ({$a})';
$string['groupavg'] = 'Group average';
$string['hidden'] = 'Hidden';
$string['hidden_help'] = 'If ticked, grades are hidden from students. A hidden until date may be set if desired, to release grades after grading is completed.';

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -343,9 +343,12 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
this.bodyJS = js;
}
}
return result;
}.bind(this))
.then(function(result) {
Event.notifyFilterContentUpdated(body);
this.getRoot().trigger(ModalEvents.bodyRendered, this);
return result;
}.bind(this))
.fail(Notification.exception)

View File

@ -195,6 +195,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/assignroles' => 'fa-user-plus',
'core:i/backup' => 'fa-file-zip-o',
'core:i/badge' => 'fa-shield',
'core:i/breadcrumbdivider' => 'fa-angle-right',
'core:i/calc' => 'fa-calculator',
'core:i/calendar' => 'fa-calendar',
'core:i/calendareventdescription' => 'fa-align-left',
@ -241,6 +242,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/grade_incorrect' => 'fa-remove text-danger',
'core:i/grade_partiallycorrect' => 'fa-check-square',
'core:i/grades' => 'fa-table',
'core:i/grading' => 'fa-magic',
'core:i/groupevent' => 'fa-group',
'core:i/groupn' => 'fa-user',
'core:i/group' => 'fa-users',

View File

@ -33,9 +33,9 @@
}}
<div
id="{{$drawerid}}drawer-{{uniqid}}{{/drawerid}}"
class="{{$drawerclasses}}{{/drawerclasses}} drawer bg-white hidden"
aria-expanded="false"
aria-hidden="true"
class="{{$drawerclasses}}{{/drawerclasses}} drawer bg-white {{^show}}hidden{{/show}}"
aria-expanded="{{#show}}true{{/show}}{{^show}}false{{/show}}"
aria-hidden="{{#show}}false{{/show}}{{^show}}true{{/show}}"
data-region="right-hand-drawer"
role="region"
tabindex="-1"

View File

@ -1,2 +1,2 @@
define ("mod_forum/grades/expandconversation",["exports","./grader/selectors","mod_forum/repository","core/notification","core/templates","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=i(b);c=h(c);e=h(e);f=i(f);g=i(g);function h(a){return a&&a.__esModule?a:{default:a}}function i(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function j(a,b){return m(a)||l(a,b)||k()}function k(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function l(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function m(a){if(Array.isArray(a))return a}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}var p=function(a){return a.closest(b.expandConversation)},q=function(){var a=o(regeneratorRuntime.mark(function a(b){var d,h,i,k,l,m,n,o,p;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=b.dataset.postid;h=b.dataset.discussionid;i=b.dataset.name;a.next=5;return Promise.all([c.default.getDiscussionPosts(parseInt(h)),f.create({title:i,large:!0,type:f.types.CANCEL})]);case 5:k=a.sent;l=j(k,2);m=l[0];n=l[1];o=m.posts.map(function(a){a.subject=null;a.readonly=!0;a.html.rating=null;return a});n.getRoot().on(g.hidden,function(){n.destroy()});n.show();p=e.default.render("mod_forum/grades/grader/discussion/post_modal",o);n.setBody(p);p.then(function(){var a=n.getRoot()[0].querySelector("#p".concat(d));if(a){a.scrollIntoView({behavior:"smooth"})}return});case 15:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.registerEventListeners=function registerEventListeners(a){a.addEventListener("click",function(a){var b=p(a.target);if(b){a.preventDefault();try{q(b)}catch(a){(0,d.exception)(a)}}})}});
define ("mod_forum/grades/expandconversation",["exports","./grader/selectors","mod_forum/repository","core/notification","core/templates","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=i(b);c=h(c);e=h(e);f=i(f);g=i(g);function h(a){return a&&a.__esModule?a:{default:a}}function i(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function j(a,b){return m(a)||l(a,b)||k()}function k(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function l(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function m(a){if(Array.isArray(a))return a}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}var p=function(a){return a.closest(b.expandConversation)},q=function(){var a=o(regeneratorRuntime.mark(function a(b){var d,h,i,k,l,m,n,o,p,q,r;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=b.dataset.postid;h=b.dataset.discussionid;i=b.dataset.name;k="1"==b.dataset.experimentalDisplayMode;a.next=6;return Promise.all([c.default.getDiscussionPosts(parseInt(h)),f.create({title:i,large:!0,type:f.types.CANCEL})]);case 6:l=a.sent;m=j(l,2);n=m[0];o=m[1];p=new Map(n.posts.map(function(a){a.readonly=!0;a.hasreplies=!1;a.replies=[];return[a.id,a]}));q=[];n.posts.forEach(function(a){if(a.parentid){var b=p.get(a.parentid);if(b){a.parentauthorname=b.author.fullname;b.hasreplies=!0;b.replies.push(a)}else{q.push(a)}}else{q.push(a)}});o.getRoot().on(g.hidden,function(){o.destroy()});o.getRoot().on(g.bodyRendered,function(){var a=o.getRoot()[0].querySelector("#p".concat(d));if(a){a.scrollIntoView({behavior:"smooth"})}});o.show();r=e.default.render("mod_forum/grades/grader/discussion/post_modal",{posts:q,experimentaldisplaymode:k});o.setBody(r);case 18:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.registerEventListeners=function registerEventListeners(a){a.addEventListener("click",function(a){var b=p(a.target);if(b){a.preventDefault();try{q(b)}catch(a){(0,d.exception)(a)}}})}});
//# sourceMappingURL=expandconversation.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("mod_forum/grades/grader",["exports","./grader/selectors","mod_forum/repository","core/templates","../local/grades/grader","core/notification","core_course/repository"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerLaunchListeners=void 0;b=i(b);c=h(c);d=h(d);e=i(e);f=h(f);g=h(g);function h(a){return a&&a.__esModule?a:{default:a}}function i(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function j(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function k(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){j(h,d,e,f,g,"next",a)}function g(a){j(h,d,e,f,g,"throw",a)}f(void 0)})}}var l={contentRegion:"mod_forum/grades/grader/discussion/posts"},m=function(a){return function(b){return c.default.getDiscussionByUserID(b,a).then(function(a){a.discussions=a.discussions.map(p);return d.default.render(l.contentRegion,a)}).catch(f.default.exception)}},n=function(a,b){return k(regeneratorRuntime.mark(function c(){var d;return regeneratorRuntime.wrap(function(c){while(1){switch(c.prev=c.next){case 0:c.next=2;return g.default.getUsersFromCourseModuleID(a,b);case 2:d=c.sent;return c.abrupt("return",d.users);case 4:case"end":return c.stop();}}},c)}))},o=function(a){return a.closest(b.gradableItem)},p=function(a){var b=new Map;a.posts.parentposts.forEach(function(a){return b.set(a.id,a)});var c=a.posts.userposts.map(function(a){a.subject=null;a.readonly=!0;a.starter=!a.parentid;a.parent=b.get(a.parentid);a.html.rating=null;return a});return{id:a.id,name:a.name,posts:c}},q=function(){var a=k(regeneratorRuntime.mark(function a(b){var c,d,f;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:c=b.dataset;a.next=3;return e.getGradingPanelFunctions("mod_forum",c.contextid,c.gradingComponent,c.gradingComponentSubtype,c.gradableItemtype);case 3:d=a.sent;f=c.group?c.group:0;a.next=7;return e.launch(n(c.cmid,f),m(c.cmid),d.getter,d.setter,{groupid:c.groupid,initialUserId:c.initialuserid,moduleName:c.name});case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.registerLaunchListeners=function registerLaunchListeners(){document.addEventListener("click",function(){var a=k(regeneratorRuntime.mark(function a(c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.matches(b.launch)){a.next=17;break}d=o(c.target);if(d){a.next=4;break}throw Error("Unable to find a gradable item");case 4:if(!d.matches(b.gradableItems.wholeForum)){a.next=16;break}c.preventDefault();a.prev=6;a.next=9;return q(d);case 9:a.next=14;break;case 11:a.prev=11;a.t0=a["catch"](6);f.default.exception(a.t0);case 14:a.next=17;break;case 16:throw Error("Unable to find a valid gradable item");case 17:case"end":return a.stop();}}},a,null,[[6,11]])}));return function(){return a.apply(this,arguments)}}())}});
define ("mod_forum/grades/grader",["exports","./grader/selectors","mod_forum/repository","core/templates","../local/grades/grader","core/notification","core_course/repository","core/url"],function(a,b,c,d,e,f,g,h){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerLaunchListeners=void 0;b=j(b);c=i(c);d=i(d);e=j(e);f=i(f);g=i(g);function i(a){return a&&a.__esModule?a:{default:a}}function j(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function k(a){for(var b=1;b<arguments.length;b++){var c=null!=arguments[b]?arguments[b]:{},d=Object.keys(c);if("function"==typeof Object.getOwnPropertySymbols){d=d.concat(Object.getOwnPropertySymbols(c).filter(function(a){return Object.getOwnPropertyDescriptor(c,a).enumerable}))}d.forEach(function(b){l(a,b,c[b])})}return a}function l(a,b,c){if(b in a){Object.defineProperty(a,b,{value:c,enumerable:!0,configurable:!0,writable:!0})}else{a[b]=c}return a}function m(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function n(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){m(h,d,e,f,g,"next",a)}function g(a){m(h,d,e,f,g,"throw",a)}f(void 0)})}}var o={contentRegion:"mod_forum/grades/grader/discussion/posts"},p=function(a,b){return function(e){return c.default.getDiscussionByUserID(e,a).then(function(a){a.discussions=a.discussions.map(s);a.experimentaldisplaymode=b?!0:!1;return d.default.render(o.contentRegion,a)}).catch(f.default.exception)}},q=function(a,b){return n(regeneratorRuntime.mark(function c(){var d;return regeneratorRuntime.wrap(function(c){while(1){switch(c.prev=c.next){case 0:c.next=2;return g.default.getUsersFromCourseModuleID(a,b);case 2:d=c.sent;return c.abrupt("return",d.users);case 4:case"end":return c.stop();}}},c)}))},r=function(a){return a.closest(b.gradableItem)},s=function(a){var b=new Map;a.posts.parentposts.forEach(function(a){return b.set(a.id,a)});var c=a.posts.userposts.map(function(a){a.readonly=!0;a.hasreplies=!1;a.replies=[];var c=a.parentid?b.get(a.parentid):null;if(c){c.hasreplies=!1;c.replies=[];c.readonly=!0;a.parentauthorname=c.author.fullname}return{parent:c,post:a}});return k({},a,{posts:c})},t=function(){var a=n(regeneratorRuntime.mark(function a(b){var c,d,f;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:c=b.dataset;a.next=3;return e.getGradingPanelFunctions("mod_forum",c.contextid,c.gradingComponent,c.gradingComponentSubtype,c.gradableItemtype);case 3:d=a.sent;f=c.group?c.group:0;a.next=7;return e.launch(q(c.cmid,f),p(c.cmid,"1"==c.experimentalDisplayMode),d.getter,d.setter,{groupid:c.groupid,initialUserId:c.initialuserid,moduleName:c.name,courseName:c.courseName,courseUrl:(0,h.relativeUrl)("/course/view.php",{id:c.courseId})});case 7:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.registerLaunchListeners=function registerLaunchListeners(){document.addEventListener("click",function(){var a=n(regeneratorRuntime.mark(function a(c){var d;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:if(!c.target.matches(b.launch)){a.next=17;break}d=r(c.target);if(d){a.next=4;break}throw Error("Unable to find a gradable item");case 4:if(!d.matches(b.gradableItems.wholeForum)){a.next=16;break}c.preventDefault();a.prev=6;a.next=9;return t(d);case 9:a.next=14;break;case 11:a.prev=11;a.t0=a["catch"](6);f.default.exception(a.t0);case 14:a.next=17;break;case 16:throw Error("Unable to find a valid gradable item");case 17:case"end":return a.stop();}}},a,null,[[6,11]])}));return function(){return a.apply(this,arguments)}}())}});
//# sourceMappingURL=grader.min.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("mod_forum/local/grades/local/grader/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={buttons:{toggleFullscreen:b("action","togglefullscreen"),closeGrader:b("action","closegrader"),saveGrade:b("action","savegrade")},regions:{moduleReplace:b("region","module_content"),pickerRegion:b("region","user_picker"),gradingPanel:b("region","grade"),gradingPanelErrors:b("region","grade-errors")}};a.default=c;return a.default});
define ("mod_forum/local/grades/local/grader/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;var b=function(a,b){return"[data-".concat(a,"=\"").concat(b,"\"]")},c={buttons:{toggleFullscreen:b("action","togglefullscreen"),closeGrader:b("action","closegrader"),saveGrade:b("action","savegrade"),selectUser:b("action","select-user"),toggleSearch:b("action","toggle-search")},regions:{bodyContainer:b("region","body-container"),moduleReplace:b("region","module_content"),pickerRegion:b("region","user_picker"),gradingPanel:b("region","grade"),gradingPanelContainer:b("region","grading-panel-container"),gradingPanelErrors:b("region","grade-errors"),searchResultsContainer:b("region","search-results-container"),statusContainer:b("region","status-container"),userSearchContainer:b("region","user-search-container"),userSearchInput:b("region","user-search-input")}};a.default=c;return a.default});
//# sourceMappingURL=selectors.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../../../../../src/local/grades/local/grader/selectors.js"],"names":["getDataSelector","name","value","buttons","toggleFullscreen","closeGrader","saveGrade","regions","moduleReplace","pickerRegion","gradingPanel","gradingPanelErrors"],"mappings":"kKA8BMA,CAAAA,CAAe,CAAG,SAACC,CAAD,CAAOC,CAAP,CAAiB,CACrC,sBAAgBD,CAAhB,eAAyBC,CAAzB,OACH,C,GAEc,CACXC,OAAO,CAAE,CACLC,gBAAgB,CAAEJ,CAAe,CAAC,QAAD,CAAW,kBAAX,CAD5B,CAELK,WAAW,CAAEL,CAAe,CAAC,QAAD,CAAW,aAAX,CAFvB,CAGLM,SAAS,CAAEN,CAAe,CAAC,QAAD,CAAW,WAAX,CAHrB,CADE,CAMXO,OAAO,CAAE,CACLC,aAAa,CAAER,CAAe,CAAC,QAAD,CAAW,gBAAX,CADzB,CAELS,YAAY,CAAET,CAAe,CAAC,QAAD,CAAW,aAAX,CAFxB,CAGLU,YAAY,CAAEV,CAAe,CAAC,QAAD,CAAW,OAAX,CAHxB,CAILW,kBAAkB,CAAEX,CAAe,CAAC,QAAD,CAAW,cAAX,CAJ9B,CANE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the grading interface.\n *\n * @module mod_forum/local/grades/local/grader/selectors\n * @package mod_forum\n * @copyright 2019 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n buttons: {\n toggleFullscreen: getDataSelector('action', 'togglefullscreen'),\n closeGrader: getDataSelector('action', 'closegrader'),\n saveGrade: getDataSelector('action', 'savegrade'),\n },\n regions: {\n moduleReplace: getDataSelector('region', 'module_content'),\n pickerRegion: getDataSelector('region', 'user_picker'),\n gradingPanel: getDataSelector('region', 'grade'),\n gradingPanelErrors: getDataSelector('region', 'grade-errors'),\n },\n};\n\n"],"file":"selectors.min.js"}
{"version":3,"sources":["../../../../../src/local/grades/local/grader/selectors.js"],"names":["getDataSelector","name","value","buttons","toggleFullscreen","closeGrader","saveGrade","selectUser","toggleSearch","regions","bodyContainer","moduleReplace","pickerRegion","gradingPanel","gradingPanelContainer","gradingPanelErrors","searchResultsContainer","statusContainer","userSearchContainer","userSearchInput"],"mappings":"kKA8BMA,CAAAA,CAAe,CAAG,SAACC,CAAD,CAAOC,CAAP,CAAiB,CACrC,sBAAgBD,CAAhB,eAAyBC,CAAzB,OACH,C,GAEc,CACXC,OAAO,CAAE,CACLC,gBAAgB,CAAEJ,CAAe,CAAC,QAAD,CAAW,kBAAX,CAD5B,CAELK,WAAW,CAAEL,CAAe,CAAC,QAAD,CAAW,aAAX,CAFvB,CAGLM,SAAS,CAAEN,CAAe,CAAC,QAAD,CAAW,WAAX,CAHrB,CAILO,UAAU,CAAEP,CAAe,CAAC,QAAD,CAAW,aAAX,CAJtB,CAKLQ,YAAY,CAAER,CAAe,CAAC,QAAD,CAAW,eAAX,CALxB,CADE,CAQXS,OAAO,CAAE,CACLC,aAAa,CAAEV,CAAe,CAAC,QAAD,CAAW,gBAAX,CADzB,CAELW,aAAa,CAAEX,CAAe,CAAC,QAAD,CAAW,gBAAX,CAFzB,CAGLY,YAAY,CAAEZ,CAAe,CAAC,QAAD,CAAW,aAAX,CAHxB,CAILa,YAAY,CAAEb,CAAe,CAAC,QAAD,CAAW,OAAX,CAJxB,CAKLc,qBAAqB,CAAEd,CAAe,CAAC,QAAD,CAAW,yBAAX,CALjC,CAMLe,kBAAkB,CAAEf,CAAe,CAAC,QAAD,CAAW,cAAX,CAN9B,CAOLgB,sBAAsB,CAAEhB,CAAe,CAAC,QAAD,CAAW,0BAAX,CAPlC,CAQLiB,eAAe,CAAEjB,CAAe,CAAC,QAAD,CAAW,kBAAX,CAR3B,CASLkB,mBAAmB,CAAElB,CAAe,CAAC,QAAD,CAAW,uBAAX,CAT/B,CAULmB,eAAe,CAAEnB,CAAe,CAAC,QAAD,CAAW,mBAAX,CAV3B,CARE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the grading interface.\n *\n * @module mod_forum/local/grades/local/grader/selectors\n * @package mod_forum\n * @copyright 2019 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n buttons: {\n toggleFullscreen: getDataSelector('action', 'togglefullscreen'),\n closeGrader: getDataSelector('action', 'closegrader'),\n saveGrade: getDataSelector('action', 'savegrade'),\n selectUser: getDataSelector('action', 'select-user'),\n toggleSearch: getDataSelector('action', 'toggle-search')\n },\n regions: {\n bodyContainer: getDataSelector('region', 'body-container'),\n moduleReplace: getDataSelector('region', 'module_content'),\n pickerRegion: getDataSelector('region', 'user_picker'),\n gradingPanel: getDataSelector('region', 'grade'),\n gradingPanelContainer: getDataSelector('region', 'grading-panel-container'),\n gradingPanelErrors: getDataSelector('region', 'grade-errors'),\n searchResultsContainer: getDataSelector('region', 'search-results-container'),\n statusContainer: getDataSelector('region', 'status-container'),\n userSearchContainer: getDataSelector('region', 'user-search-container'),\n userSearchInput: getDataSelector('region', 'user-search-input')\n },\n};\n\n"],"file":"selectors.min.js"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("mod_forum/local/grades/local/grader/user_picker/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={regions:{userRegion:"[data-region=\"user_picker/user\"]"},actions:{changeUser:"[data-action=\"change-user\"]",selectUser:"[data-action=\"select-user\"]",searchUserBox:"[data-action=\"search-user-box\"]",searchUserInput:"[data-action=\"search-user-input\"]"}};return a.default});
define ("mod_forum/local/grades/local/grader/user_picker/selectors",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.default=void 0;a.default={regions:{userRegion:"[data-region=\"user_picker/user\"]"},actions:{changeUser:"[data-action=\"change-user\"]"}};return a.default});
//# sourceMappingURL=selectors.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../../../../../../src/local/grades/local/grader/user_picker/selectors.js"],"names":["regions","userRegion","actions","changeUser","selectUser","searchUserBox","searchUserInput"],"mappings":"qLAwBe,CACXA,OAAO,CAAE,CACLC,UAAU,CAAE,oCADP,CADE,CAIXC,OAAO,CAAE,CACLC,UAAU,CAAE,+BADP,CAELC,UAAU,CAAE,+BAFP,CAGLC,aAAa,CAAE,mCAHV,CAILC,eAAe,CAAE,qCAJZ,CAJE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the grading interface.\n *\n * @module mod_forum/local/grades/local/grader/user_picker/selectors\n * @package mod_forum\n * @copyright 2019 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n regions: {\n userRegion: '[data-region=\"user_picker/user\"]',\n },\n actions: {\n changeUser: '[data-action=\"change-user\"]',\n selectUser: '[data-action=\"select-user\"]',\n searchUserBox: '[data-action=\"search-user-box\"]',\n searchUserInput: '[data-action=\"search-user-input\"]',\n }\n};\n\n"],"file":"selectors.min.js"}
{"version":3,"sources":["../../../../../../src/local/grades/local/grader/user_picker/selectors.js"],"names":["regions","userRegion","actions","changeUser"],"mappings":"qLAwBe,CACXA,OAAO,CAAE,CACLC,UAAU,CAAE,oCADP,CADE,CAIXC,OAAO,CAAE,CACLC,UAAU,CAAE,+BADP,CAJE,C","sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the grading interface.\n *\n * @module mod_forum/local/grades/local/grader/user_picker/selectors\n * @package mod_forum\n * @copyright 2019 Mathew May <mathew.solutions>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nexport default {\n regions: {\n userRegion: '[data-region=\"user_picker/user\"]',\n },\n actions: {\n changeUser: '[data-action=\"change-user\"]',\n }\n};\n\n"],"file":"selectors.min.js"}

View File

@ -45,6 +45,7 @@ const showPostInContext = async(rootNode) => {
const postId = rootNode.dataset.postid;
const discussionId = rootNode.dataset.discussionid;
const discussionName = rootNode.dataset.name;
const experimentalDisplayMode = rootNode.dataset.experimentalDisplayMode == "1";
const [
allPosts,
@ -58,12 +59,27 @@ const showPostInContext = async(rootNode) => {
}),
]);
const userPosts = allPosts.posts.map((post) => {
post.subject = null;
const postsById = new Map(allPosts.posts.map(post => {
post.readonly = true;
post.html.rating = null;
post.hasreplies = false;
post.replies = [];
return [post.id, post];
}));
return post;
let posts = [];
allPosts.posts.forEach(post => {
if (post.parentid) {
const parent = postsById.get(post.parentid);
if (parent) {
post.parentauthorname = parent.author.fullname;
parent.hasreplies = true;
parent.replies.push(post);
} else {
posts.push(post);
}
} else {
posts.push(post);
}
});
// Handle hidden event.
@ -72,20 +88,21 @@ const showPostInContext = async(rootNode) => {
modal.destroy();
});
modal.show();
// Note: We do not use await here because it messes with the Modal transitions.
const templatePromise = Templates.render('mod_forum/grades/grader/discussion/post_modal', userPosts);
modal.setBody(templatePromise);
// eslint-disable-next-line promise/catch-or-return
templatePromise.then(() => {
modal.getRoot().on(ModalEvents.bodyRendered, () => {
const relevantPost = modal.getRoot()[0].querySelector(`#p${postId}`);
if (relevantPost) {
relevantPost.scrollIntoView({behavior: "smooth"});
}
return;
});
modal.show();
// Note: We do not use await here because it messes with the Modal transitions.
const templatePromise = Templates.render('mod_forum/grades/grader/discussion/post_modal', {
posts,
experimentaldisplaymode: experimentalDisplayMode
});
modal.setBody(templatePromise);
};
/**

View File

@ -27,6 +27,7 @@ import Templates from 'core/templates';
import * as Grader from '../local/grades/grader';
import Notification from 'core/notification';
import CourseRepository from 'core_course/repository';
import {relativeUrl} from 'core/url';
const templateNames = {
contentRegion: 'mod_forum/grades/grader/discussion/posts',
@ -36,9 +37,10 @@ const templateNames = {
* Curried function with CMID set, this is then used in unified grader as a fetch a users content.
*
* @param {Number} cmid
* @param {Bool} experimentalDisplayMode
* @return {Function}
*/
const getContentForUserIdFunction = (cmid) => (userid) => {
const getContentForUserIdFunction = (cmid, experimentalDisplayMode) => (userid) => {
/**
* Given the parent function is called with the second param set execute the partially executed function.
*
@ -48,6 +50,7 @@ const getContentForUserIdFunction = (cmid) => (userid) => {
.then(context => {
// Rebuild the returned data for the template.
context.discussions = context.discussions.map(discussionPostMapper);
context.experimentaldisplaymode = experimentalDisplayMode ? true : false;
return Templates.render(templateNames.contentRegion, context);
})
@ -82,18 +85,26 @@ const discussionPostMapper = (discussion) => {
const parentMap = new Map();
discussion.posts.parentposts.forEach(post => parentMap.set(post.id, post));
const userPosts = discussion.posts.userposts.map(post => {
post.subject = null;
post.readonly = true;
post.starter = !post.parentid;
post.parent = parentMap.get(post.parentid);
post.html.rating = null;
post.hasreplies = false;
post.replies = [];
return post;
const parent = post.parentid ? parentMap.get(post.parentid) : null;
if (parent) {
parent.hasreplies = false;
parent.replies = [];
parent.readonly = true;
post.parentauthorname = parent.author.fullname;
}
return {
parent,
post
};
});
return {
id: discussion.id,
name: discussion.name,
...discussion,
posts: userPosts,
};
};
@ -117,13 +128,15 @@ const launchWholeForumGrading = async(rootNode) => {
await Grader.launch(
getUsersForCmidFunction(data.cmid, groupID),
getContentForUserIdFunction(data.cmid),
getContentForUserIdFunction(data.cmid, data.experimentalDisplayMode == "1"),
gradingPanelFunctions.getter,
gradingPanelFunctions.setter,
{
groupid: data.groupid,
initialUserId: data.initialuserid,
moduleName: data.name
moduleName: data.name,
courseName: data.courseName,
courseUrl: relativeUrl('/course/view.php', {id: data.courseId})
}
);
};

View File

@ -30,6 +30,7 @@ import {add as addToast} from 'core/toast';
import {get_string as getString} from 'core/str';
import {failedUpdate} from 'core_grades/grades/grader/gradingpanel/normalise';
import {addIconToContainerWithPromise} from 'core/loadingicon';
import {debounce} from 'core/utils';
const templateNames = {
grader: {
@ -37,6 +38,8 @@ const templateNames = {
gradingPanel: {
error: 'mod_forum/local/grades/local/grader/gradingpanel/error',
},
searchResults: 'mod_forum/local/grades/local/grader/user_picker/user_search',
status: 'mod_forum/local/grades/local/grader/status',
},
};
@ -72,8 +75,10 @@ const fetchContentFromRender = (html, js) => {
* @return {Function}
*/
const getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser) => {
let firstLoad = true;
return async(user) => {
const spinner = addIconToContainerWithPromise(root);
const spinner = firstLoad ? null : addIconToContainerWithPromise(root);
const [
[html, js],
userGrade,
@ -87,20 +92,122 @@ const getUpdateUserContentFunction = (root, getContentForUser, getGradeForUser)
gradingPanelHtml,
gradingPanelJS
] = await Templates.render(userGrade.templatename, userGrade.grade).then(fetchContentFromRender);
Templates.replaceNodeContents(root.querySelector(Selectors.regions.gradingPanel), gradingPanelHtml, gradingPanelJS);
spinner.resolve();
const panelContainer = root.querySelector(Selectors.regions.gradingPanelContainer);
const panel = panelContainer.querySelector(Selectors.regions.gradingPanel);
Templates.replaceNodeContents(panel, gradingPanelHtml, gradingPanelJS);
panelContainer.scrollTop = 0;
firstLoad = false;
if (spinner) {
spinner.resolve();
}
};
};
/**
* Show the search results container and hide the user picker and body content.
*
* @param {HTMLElement} bodyContainer The container element for the body content
* @param {HTMLElement} userPickerContainer The container element for the user picker
* @param {HTMLElement} searchResultsContainer The container element for the search results
*/
const showSearchResultContainer = (bodyContainer, userPickerContainer, searchResultsContainer) => {
bodyContainer.classList.add('hidden');
userPickerContainer.classList.add('hidden');
searchResultsContainer.classList.remove('hidden');
};
/**
* Hide the search results container and show the user picker and body content.
*
* @param {HTMLElement} bodyContainer The container element for the body content
* @param {HTMLElement} userPickerContainer The container element for the user picker
* @param {HTMLElement} searchResultsContainer The container element for the search results
*/
const hideSearchResultContainer = (bodyContainer, userPickerContainer, searchResultsContainer) => {
bodyContainer.classList.remove('hidden');
userPickerContainer.classList.remove('hidden');
searchResultsContainer.classList.add('hidden');
};
/**
* Toggles the visibility of the user search.
*
* @param {HTMLElement} toggleSearchButton The button that toggles the search
* @param {HTMLElement} searchContainer The container element for the user search
* @param {HTMLElement} searchInput The input element for searching
*/
const showUserSearchInput = (toggleSearchButton, searchContainer, searchInput) => {
searchContainer.classList.remove('collapsed');
toggleSearchButton.setAttribute('aria-expanded', 'true');
toggleSearchButton.classList.add('expand');
toggleSearchButton.classList.remove('collapse');
searchInput.focus();
};
/**
* Toggles the visibility of the user search.
*
* @param {HTMLElement} toggleSearchButton The button that toggles the search
* @param {HTMLElement} searchContainer The container element for the user search
* @param {HTMLElement} searchInput The input element for searching
*/
const hideUserSearchInput = (toggleSearchButton, searchContainer, searchInput) => {
searchContainer.classList.add('collapsed');
toggleSearchButton.setAttribute('aria-expanded', 'false');
toggleSearchButton.classList.add('collapse');
toggleSearchButton.classList.remove('expand');
toggleSearchButton.focus();
searchInput.value = '';
};
/**
* Find the list of users who's names include the given search term.
*
* @param {Array} userList List of users for the grader
* @param {String} searchTerm The search term to match
* @return {Array}
*/
const searchForUsers = (userList, searchTerm) => {
if (searchTerm === '') {
return userList;
}
searchTerm = searchTerm.toLowerCase();
return userList.filter((user) => {
return user.fullname.toLowerCase().includes(searchTerm);
});
};
/**
* Render the list of users in the search results area.
*
* @param {HTMLElement} searchResultsContainer The container element for search results
* @param {Array} users The list of users to display
*/
const renderSearchResults = async (searchResultsContainer, users) => {
const {html, js} = await Templates.renderForPromise(templateNames.grader.searchResults, {users});
Templates.replaceNodeContents(searchResultsContainer, html, js);
};
/**
* Add click handlers to the buttons in the header of the grading interface.
*
* @param {HTMLElement} graderLayout
* @param {Object} userPicker
* @param {Function} saveGradeFunction
* @param {Array} userList List of users for the grader.
*/
const registerEventListeners = (graderLayout, userPicker, saveGradeFunction) => {
const registerEventListeners = (graderLayout, userPicker, saveGradeFunction, userList) => {
const graderContainer = graderLayout.getContainer();
const toggleSearchButton = graderContainer.querySelector(Selectors.buttons.toggleSearch);
const searchInputContainer = graderContainer.querySelector(Selectors.regions.userSearchContainer);
const searchInput = searchInputContainer.querySelector(Selectors.regions.userSearchInput);
const bodyContainer = graderContainer.querySelector(Selectors.regions.bodyContainer);
const userPickerContainer = graderContainer.querySelector(Selectors.regions.pickerRegion);
const searchResultsContainer = graderContainer.querySelector(Selectors.regions.searchResultsContainer);
graderContainer.addEventListener('click', (e) => {
if (e.target.closest(Selectors.buttons.toggleFullscreen)) {
e.stopImmediatePropagation();
@ -122,7 +229,40 @@ const registerEventListeners = (graderLayout, userPicker, saveGradeFunction) =>
if (e.target.closest(Selectors.buttons.saveGrade)) {
saveGradeFunction(userPicker.currentUser);
}
if (e.target.closest(Selectors.buttons.toggleSearch)) {
if (toggleSearchButton.getAttribute('aria-expanded') === 'true') {
// Search is open so let's close it.
hideUserSearchInput(toggleSearchButton, searchInputContainer, searchInput);
hideSearchResultContainer(bodyContainer, userPickerContainer, searchResultsContainer);
searchResultsContainer.innerHTML = '';
} else {
// Search is closed so let's open it.
showUserSearchInput(toggleSearchButton, searchInputContainer, searchInput);
showSearchResultContainer(bodyContainer, userPickerContainer, searchResultsContainer);
renderSearchResults(searchResultsContainer, userList);
}
return;
}
const selectUserButton = e.target.closest(Selectors.buttons.selectUser);
if (selectUserButton) {
const userId = selectUserButton.getAttribute('data-userid');
const user = userList.find(user => user.id == userId);
userPicker.setUserId(userId);
userPicker.showUser(user);
hideUserSearchInput(toggleSearchButton, searchInputContainer, searchInput);
hideSearchResultContainer(bodyContainer, userPickerContainer, searchResultsContainer);
searchResultsContainer.innerHTML = '';
}
});
// Debounce the search input so that it only executes 300 milliseconds after the user has finished typing.
searchInput.addEventListener('input', debounce(() => {
const users = searchForUsers(userList, searchInput.value);
renderSearchResults(searchResultsContainer, users);
}, 300));
};
/**
@ -182,31 +322,49 @@ const displayGradingError = async(root, user, err) => {
* @param {Function} setGradeForUser A function to set the grade for a specific user
*/
export const launch = async(getListOfUsers, getContentForUser, getGradeForUser, setGradeForUser, {
initialUserId = null, moduleName
initialUserId = null, moduleName, courseName, courseUrl
} = {}) => {
// We need all of these functions to be executed in series, if one step runs before another the interface
// will not work.
const [
graderLayout,
graderHTML,
{html, js},
userList,
] = await Promise.all([
createFullScreenWindow({fullscreen: false, showLoader: false}),
Templates.render(templateNames.grader.app, {moduleName: moduleName}),
Templates.renderForPromise(templateNames.grader.app, {
moduleName,
courseName,
courseUrl,
drawer: {show: true}
}),
getListOfUsers(),
]);
const graderContainer = graderLayout.getContainer();
const saveGradeFunction = getSaveUserGradeFunction(graderContainer, setGradeForUser);
Templates.replaceNodeContents(graderContainer, graderHTML, '');
Templates.replaceNodeContents(graderContainer, html, js);
const updateUserContent = getUpdateUserContentFunction(graderContainer, getContentForUser, getGradeForUser);
const userIds = userList.map(user => user.id);
const statusContainer = graderContainer.querySelector(Selectors.regions.statusContainer);
// Fetch the userpicker for display.
const userPicker = await getUserPicker(
userList,
updateUserContent,
user => {
const renderContext = {
status: null,
index: userIds.indexOf(user.id) + 1,
total: userList.length
};
Templates.render(templateNames.grader.status, renderContext).then(html => {
statusContainer.innerHTML = html;
return html;
}).catch();
updateUserContent(user);
},
saveGradeFunction,
{
initialUserId,
@ -214,7 +372,7 @@ export const launch = async(getListOfUsers, getContentForUser, getGradeForUser,
);
// Register all event listeners.
registerEventListeners(graderLayout, userPicker, saveGradeFunction);
registerEventListeners(graderLayout, userPicker, saveGradeFunction, userList);
// Display the newly created user picker.
displayUserPicker(graderContainer, userPicker.rootNode);

View File

@ -37,12 +37,20 @@ export default {
toggleFullscreen: getDataSelector('action', 'togglefullscreen'),
closeGrader: getDataSelector('action', 'closegrader'),
saveGrade: getDataSelector('action', 'savegrade'),
selectUser: getDataSelector('action', 'select-user'),
toggleSearch: getDataSelector('action', 'toggle-search')
},
regions: {
bodyContainer: getDataSelector('region', 'body-container'),
moduleReplace: getDataSelector('region', 'module_content'),
pickerRegion: getDataSelector('region', 'user_picker'),
gradingPanel: getDataSelector('region', 'grade'),
gradingPanelContainer: getDataSelector('region', 'grading-panel-container'),
gradingPanelErrors: getDataSelector('region', 'grade-errors'),
searchResultsContainer: getDataSelector('region', 'search-results-container'),
statusContainer: getDataSelector('region', 'status-container'),
userSearchContainer: getDataSelector('region', 'user-search-container'),
userSearchInput: getDataSelector('region', 'user-search-input')
},
};

View File

@ -79,10 +79,6 @@ class UserPicker {
// Call the showUser function to show the first user immediately.
await this.showUser(this.currentUser);
// Show a list of users under the user search box.
await this.renderSearch(this.userList);
this.searchResultListener();
// Ensure that the event listeners are all bound.
this.registerEventListeners();
}
@ -123,7 +119,6 @@ class UserPicker {
registerEventListeners() {
this.root.addEventListener('click', async(e) => {
const button = e.target.closest(Selectors.actions.changeUser);
const input = e.target.closest(Selectors.actions.searchUserInput);
if (button) {
const result = await this.preChangeUserCallback(this.currentUser);
@ -133,87 +128,17 @@ class UserPicker {
await this.showUser(this.currentUser);
}
}
if (input) {
// Make the key up a seperate function.
this.onKeyUp(input);
}
});
}
/**
* Listener for keyboard entry that'll search the user list for matching users.
*
* @param {Text} input User entered text of the user to search for.
*/
onKeyUp(input) {
// Init a timeout variable to be used below
let timeout = null;
// Listen for keystroke events
input.onkeyup = () => {
// Clear the timeout if it has already been set.
clearTimeout(timeout);
// Make a new timeout set to go off in 300ms
timeout = setTimeout(async(userList) => {
const userInput = input.value;
const results = userList.filter((user) => {
return user.fullname.toLowerCase().includes(userInput.toLowerCase());
});
await this.renderSearch(results);
this.searchResultListener();
}, 300, this.userList);
};
}
/**
* Apply the click handler for the users found in the user search area.
*/
searchResultListener() {
this.root.querySelector(Selectors.actions.searchUserBox).addEventListener('click', async(e) => {
e.preventDefault();
const user = e.target.closest(Selectors.actions.selectUser);
if (user !== null) {
const foundUser = this.userList.findIndex(item => parseInt(item.id) === parseInt(user.dataset.userid));
const result = await this.preChangeUserCallback(this.currentUser);
if (!result.failed) {
this.updateIndex(0, parseInt(foundUser));
await this.showUser(this.currentUser);
}
}
});
}
/**
* Render the user search results.
*
* @param {Array} results List of users
*/
async renderSearch(results) {
const trimmedUsers = results.slice(0, 10);
const overflowUsers = results.slice(10);
const builtResults = {
'expandedUsers': trimmedUsers,
'hasCollapsed': overflowUsers.length > 0,
'collapsedUsers': overflowUsers,
};
const {html, js} = await Templates.renderForPromise(`${templatePath}/user_picker/user_search`, builtResults);
const searchUserRegion = this.root.querySelector(Selectors.actions.searchUserBox);
Templates.replaceNode(searchUserRegion, html, js);
}
/**
* Update the current user index.
*
* @param {Number} direction
* @param {Number} specificIndex
* @returns {Number}}
*/
updateIndex(direction, specificIndex = null) {
if (specificIndex) {
this.currentUserIndex = specificIndex;
} else {
this.currentUserIndex += direction;
}
updateIndex(direction) {
this.currentUserIndex += direction;
// Loop around the edges.
if (this.currentUserIndex < 0) {

View File

@ -28,9 +28,6 @@ export default {
},
actions: {
changeUser: '[data-action="change-user"]',
selectUser: '[data-action="select-user"]',
searchUserBox: '[data-action="search-user-box"]',
searchUserInput: '[data-action="search-user-input"]',
}
};

View File

@ -91,7 +91,7 @@ class forum_gradeitem extends component_gradeitem {
* @return bool
*/
public function is_grading_enabled(): bool {
return $this->forum->get_grade_for_forum() !== 0;
return $this->forum->is_grading_enabled();
}
/**

View File

@ -363,6 +363,15 @@ class forum {
return $this->gradeforum;
}
/**
* Whether grading is enabled for this item.
*
* @return bool
*/
public function is_grading_enabled(): bool {
return $this->get_grade_for_forum() !== 0;
}
/**
* Get the maximum bytes.
*

View File

@ -65,6 +65,7 @@ class forum extends exporter {
'state' => [
'type' => [
'groupmode' => ['type' => PARAM_INT],
'gradingenabled' => ['type' => PARAM_BOOL],
],
],
'userstate' => [
@ -77,6 +78,7 @@ class forum extends exporter {
'viewdiscussions' => ['type' => PARAM_BOOL],
'create' => ['type' => PARAM_BOOL],
'subscribe' => ['type' => PARAM_BOOL],
'grade' => ['type' => PARAM_BOOL],
]
],
'urls' => [
@ -120,6 +122,7 @@ class forum extends exporter {
'name' => $this->forum->get_name(),
'state' => [
'groupmode' => $this->forum->get_effective_group_mode(),
'gradingenabled' => $this->forum->is_grading_enabled()
],
'userstate' => [
'tracked' => forum_tp_is_tracked($this->get_forum_record(), $this->related['user']),
@ -129,6 +132,7 @@ class forum extends exporter {
'create' => $capabilitymanager->can_create_discussions($user, $currentgroup),
'selfenrol' => $capabilitymanager->can_self_enrol($user),
'subscribe' => $capabilitymanager->can_subscribe_to_forum($user),
'grade' => $capabilitymanager->can_grade($user),
],
'urls' => [
'create' => $urlfactory->get_discussion_create_url($this->forum)->out(false),

View File

@ -144,12 +144,22 @@ class discussion_list {
* @param int $sortorder The sort order to use when selecting the discussions in the list
* @param int $pageno The zero-indexed page number to use
* @param int $pagesize The number of discussions to show on the page
* @param int $displaymode The discussion display mode
* @return string The rendered content for display
*/
public function render(stdClass $user, \cm_info $cm, ?int $groupid, ?int $sortorder, ?int $pageno, ?int $pagesize) : string {
public function render(
stdClass $user,
\cm_info $cm,
?int $groupid,
?int $sortorder,
?int $pageno,
?int $pagesize,
int $displaymode = null
) : string {
global $PAGE;
$forum = $this->forum;
$course = $forum->get_course_record();
$forumexporter = $this->exporterfactory->get_forum_exporter(
$user,
@ -176,6 +186,10 @@ class discussion_list {
'forum' => (array) $forumexporter->export($this->renderer),
'contextid' => $forum->get_context()->id,
'cmid' => $cm->id,
'name' => $forum->get_name(),
'courseid' => $course->id,
'coursename' => $course->shortname,
'experimentaldisplaymode' => $displaymode == FORUM_MODE_NESTED_V2,
'gradingcomponent' => $this->forumgradeitem->get_grading_component_name(),
'gradingcomponentsubtype' => $this->forumgradeitem->get_grading_component_subtype(),
'hasanyactions' => $hasanyactions,

View File

@ -2205,8 +2205,15 @@ class mod_forum_external extends external_api {
$managerfactory = mod_forum\local\container::get_manager_factory();
$capabilitymanager = $managerfactory->get_capability_manager($forum);
$discussionvault = $vaultfactory->get_discussion_vault();
$discussions = $discussionvault->get_all_discussions_in_forum($forum, 'timemodified ASC, id ASC');
$discussionsummariesvault = $vaultfactory->get_discussions_in_forum_vault();
$discussionsummaries = $discussionsummariesvault->get_from_forum_id(
$forum->get_id(),
true,
null,
$discussionsummariesvault::SORTORDER_CREATED_ASC,
0,
0
);
$postvault = $vaultfactory->get_post_vault();
@ -2214,7 +2221,8 @@ class mod_forum_external extends external_api {
$postbuilder = $builderfactory->get_exported_posts_builder();
$builtdiscussions = [];
foreach ($discussions as $id => $discussion) {
foreach ($discussionsummaries as $discussionsummary) {
$discussion = $discussionsummary->get_discussion();
$posts = $postvault->get_posts_in_discussion_for_user_id(
$discussion->get_id(),
$user->id,
@ -2239,9 +2247,14 @@ class mod_forum_external extends external_api {
);
}
$discussionauthor = $discussionsummary->get_first_post_author();
$firstpost = $discussionsummary->get_first_post();
$builtdiscussions[] = [
'name' => $discussion->get_name(),
'id' => $discussion->get_id(),
'timecreated' => $firstpost->get_time_created(),
'authorfullname' => $discussionauthor->get_full_name(),
'posts' => [
'userposts' => $postbuilder->build($user, [$forum], [$discussion], $posts),
'parentposts' => $parentposts,
@ -2284,6 +2297,8 @@ class mod_forum_external extends external_api {
new external_single_structure([
'name' => new external_value(PARAM_RAW, 'Name of the discussion'),
'id' => new external_value(PARAM_INT, 'ID of the discussion'),
'timecreated' => new external_value(PARAM_INT, 'Timestamp of the discussion start'),
'authorfullname' => new external_value(PARAM_RAW, 'Full name of the user that started the discussion'),
'posts' => new external_single_structure([
'userposts' => new external_multiple_structure(\mod_forum\local\exporters\post::get_read_structure()),
'parentposts' => new external_multiple_structure(\mod_forum\local\exporters\post::get_read_structure()),

View File

@ -101,6 +101,7 @@ $string['clicktounsubscribe'] = 'You are subscribed to this discussion. Click to
$string['clicktosubscribe'] = 'You are not subscribed to this discussion. Click to subscribe.';
$string['clicktounfavourite'] = 'You have starred this discussion. Click to unstar.';
$string['clicktofavourite'] = 'You have not starred this discussion. Click to star.';
$string['close'] = 'Close';
$string['completiondiscussions'] = 'Student must create discussions:';
$string['completiondiscussionsdesc'] = 'Student must create at least {$a} discussion(s)';
$string['completiondiscussionsgroup'] = 'Require discussions';
@ -194,6 +195,7 @@ $string['discussionsubscription'] = 'Discussion subscription';
$string['discussionsubscription_help'] = 'Subscribing to a discussion means you will receive notifications of new posts to that discussion.';
$string['discussions'] = 'Discussions';
$string['discussionsstartedby'] = 'Discussions started by {$a}';
$string['discussionstartedby'] = 'Discussion started by {$a}';
$string['discussionsstartedbyrecent'] = 'Discussions recently started by {$a}';
$string['discussionsstartedbyuserincourse'] = 'Discussions started by {$a->fullname} in {$a->coursename}';
$string['discussionunpin'] = 'Unpin';
@ -333,7 +335,9 @@ $string['generalforum'] = 'Standard forum for general use';
$string['generalforums'] = 'General forums';
$string['gradeitem:forum'] = 'Forum';
$string['hiddenforumpost'] = 'Hidden forum post';
$string['hidegraderpanel'] = 'Hide grader panel';
$string['hidepreviousrepliescount'] = 'Hide previous replies ({$a})';
$string['hideusersearch'] = 'Hide user search';
$string['indicator:cognitivedepth'] = 'Forum cognitive';
$string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Forum activity.';
$string['indicator:cognitivedepthdef'] = 'Forum cognitive';
@ -345,6 +349,7 @@ $string['indicator:socialbreadthdef'] = 'Forum social';
$string['indicator:socialbreadthdef_help'] = 'The participant has reached this percentage of the social engagement offered by the Forum activities during this analysis interval (Levels = No participation, Participant alone, Participant with others)';
$string['indicator:socialbreadthdef_link'] = 'Learning_analytics_indicators#Social_breadth';
$string['starredonly'] = 'Search starred discussions only';
$string['indexoutoftotal'] = '{$a->index} out of {$a->total}';
$string['inforum'] = 'in {$a}';
$string['inreplyto'] = 'In reply to {$a}';
$string['introblog'] = 'The posts in this forum were copied here automatically from blogs of users in this course because those blog entries are no longer available';
@ -436,6 +441,7 @@ $string['namenews_help'] = 'The course announcements forum is a special forum fo
$string['namesocial'] = 'Social forum';
$string['nameteacher'] = 'Teacher forum';
$string['nextdiscussiona'] = 'Next discussion: {$a}';
$string['nextuser'] = 'Next user';
$string['newforumposts'] = 'New forum posts';
$string['noattachments'] = 'There are no attachments to this post';
$string['nodiscussions'] = 'There are no discussion topics yet in this forum';
@ -514,6 +520,7 @@ $string['poststo'] = 'Posts to';
$string['posttoforum'] = 'Post to forum';
$string['postupdated'] = 'Your post was updated';
$string['potentialsubscribers'] = 'Potential subscribers';
$string['previoususer'] = 'Previous user';
$string['privacy:digesttypenone'] = 'We do not hold any data relating to a preferred forum digest type for this forum.';
$string['privacy:digesttypepreference'] = 'You have chosen to receive the following forum digest type: "{$a->type}".';
$string['privacy:discussionsubscriptionpreference'] = 'You have chosen the following discussion subscription preference for this forum: "{$a->preference}"';
@ -627,6 +634,7 @@ $string['searchresults'] = 'Search results';
$string['searchsubject'] = 'These words should be in the subject';
$string['searchtags'] = 'Is tagged with';
$string['searchuser'] = 'This name should match the author';
$string['searchusers'] = 'Search users';
$string['searchuserid'] = 'The Moodle ID of the author';
$string['searchwhichforums'] = 'Choose which forums to search';
$string['searchwords'] = 'These words can appear anywhere in the post';
@ -634,8 +642,10 @@ $string['seeallposts'] = 'See all posts made by this user';
$string['settings'] = 'Settings';
$string['shortpost'] = 'Short post';
$string['showingcountoftotaldiscussions'] = 'Showing {$a->count} of {$a->total} discussions';
$string['showgraderpanel'] = 'Show grader panel';
$string['showpreviousrepliescount'] = 'Show previous replies ({$a})';
$string['showsubscribers'] = 'Show/edit current subscribers';
$string['showusersearch'] = 'Show user search';
$string['singleforum'] = 'A single simple discussion';
$string['smallmessage'] = '{$a->user} posted in {$a->forumname}';
$string['smallmessagedigest'] = 'Forum digest containing {$a} messages';
@ -677,6 +687,7 @@ $string['timedhidden'] = 'Timed status: Hidden from students';
$string['timedposts'] = 'Timed posts';
$string['timedvisible'] = 'Timed status: Visible to all users';
$string['timestartenderror'] = 'Display end date cannot be earlier than the start date';
$string['togglefullscreen'] = 'Toggle full screen';
$string['togglesettingsdrawer'] = 'Toggle settings drawer';
$string['trackforum'] = 'Track unread posts';
$string['trackreadposts_header'] = 'Forum tracking';
@ -710,8 +721,10 @@ $string['unsubscribed'] = 'Unsubscribed';
$string['unsubscribeshort'] = 'Unsubscribe';
$string['useexperimentalui'] = 'Use experimental nested discussion view';
$string['usermarksread'] = 'Manual message read marking';
$string['usernavigation'] = 'User navigation';
$string['unpindiscussion'] = 'Unpin this discussion';
$string['viewalldiscussions'] = 'View all discussions';
$string['viewparentpost'] = 'View parent post';
$string['viewthediscussion'] = 'View the discussion';
$string['warnafter'] = 'Post threshold for warning';
$string['warnafter_help'] = 'Students can be warned as they approach the maximum number of posts allowed in a given period. This setting specifies after how many posts they are warned. Users with the capability mod/forum:postwithoutthrottling are exempt from post limits.';

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="23px" height="24px" viewBox="0 0 23 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>Group 3</title>
<desc>Created with Sketch.</desc>
<g id="Grading" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Grading-Copy-4" transform="translate(-1072.000000, -21.000000)">
<g id="Group-3" transform="translate(1072.000000, 21.500000)">
<g id="left-arrow" transform="translate(0.000000, 6.795455)" fill="#000000" fill-rule="nonzero">
<path d="M9.86688101,3.53622875 L9.8832003,3.5397986 L2.88749446,3.5397986 L5.08668884,1.33575942 C5.19437916,1.2281541 5.25345159,1.08238544 5.25345159,0.929392092 C5.25345159,0.776398744 5.19437916,0.631650037 5.08668884,0.523789727 L4.74449372,0.181424612 C4.6368884,0.0738192905 4.49349963,0.0143218773 4.34059128,0.0143218773 C4.18759793,0.0143218773 4.04412417,0.0733943089 3.93651885,0.18099963 L0.166677753,3.95050074 C0.0586474501,4.05853104 -0.000424981523,4.20242979 -2.27716707e-06,4.35550813 C-0.000424981523,4.50943644 0.0586474501,4.65342018 0.166677753,4.76128049 L3.93651885,8.53112158 C4.04412417,8.63864191 4.18751293,8.69779933 4.34059128,8.69779933 C4.49349963,8.69779933 4.6368884,8.63855691 4.74449372,8.53112158 L5.08668884,8.18875647 C5.19437916,8.08132114 5.25345159,7.93784738 5.25345159,7.78485403 C5.25345159,7.63194568 5.19437916,7.49603659 5.08668884,7.38851626 L2.86267554,5.17215262 L9.87470067,5.17215262 C10.189782,5.17215262 10.4545455,4.90058943 10.4545455,4.58567812 L10.4545455,4.10145418 C10.4545455,3.78654287 10.1819623,3.53622875 9.86688101,3.53622875 Z" id="Path"></path>
</g>
<g id="left-arrow" transform="translate(17.772727, 11.151515) rotate(180.000000) translate(-17.772727, -11.151515) translate(12.545455, 6.795455)" fill="#000000" fill-rule="nonzero">
<path d="M9.86688101,3.53622875 L9.8832003,3.5397986 L2.88749446,3.5397986 L5.08668884,1.33575942 C5.19437916,1.2281541 5.25345159,1.08238544 5.25345159,0.929392092 C5.25345159,0.776398744 5.19437916,0.631650037 5.08668884,0.523789727 L4.74449372,0.181424612 C4.6368884,0.0738192905 4.49349963,0.0143218773 4.34059128,0.0143218773 C4.18759793,0.0143218773 4.04412417,0.0733943089 3.93651885,0.18099963 L0.166677753,3.95050074 C0.0586474501,4.05853104 -0.000424981523,4.20242979 -2.27716707e-06,4.35550813 C-0.000424981523,4.50943644 0.0586474501,4.65342018 0.166677753,4.76128049 L3.93651885,8.53112158 C4.04412417,8.63864191 4.18751293,8.69779933 4.34059128,8.69779933 C4.49349963,8.69779933 4.6368884,8.63855691 4.74449372,8.53112158 L5.08668884,8.18875647 C5.19437916,8.08132114 5.25345159,7.93784738 5.25345159,7.78485403 C5.25345159,7.63194568 5.19437916,7.49603659 5.08668884,7.38851626 L2.86267554,5.17215262 L9.87470067,5.17215262 C10.189782,5.17215262 10.4545455,4.90058943 10.4545455,4.58567812 L10.4545455,4.10145418 C10.4545455,3.78654287 10.1819623,3.53622875 9.86688101,3.53622875 Z" id="Path"></path>
</g>
<g id="Group-2" transform="translate(0.522727, 0.000000)" stroke="#000000" stroke-linecap="square" stroke-width="2">
<path d="M0.522727273,0.522727273 L21.4318182,0.522727273 M0.522727273,0.522727273 L0.522727273,3.13636364 M21.4318182,0.522727273 L21.4318182,3.13636364" id="Combined-Shape"></path>
</g>
<g id="Group-2" transform="translate(11.500000, 21.431818) scale(1, -1) translate(-11.500000, -21.431818) translate(0.522727, 19.863636)" stroke="#000000" stroke-linecap="square" stroke-width="2">
<path d="M0.522727273,0.522727273 L21.4318182,0.522727273 M0.522727273,0.522727273 L0.522727273,3.13636364 M21.4318182,0.522727273 L21.4318182,3.13636364" id="Combined-Shape"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
mod/forum/pix/no-posts.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>show</title>
<desc>Created with Sketch.</desc>
<g id="Grading" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Grading-Copy-4" transform="translate(-1070.000000, -21.000000)" fill="#000000" fill-rule="nonzero">
<g id="show" transform="translate(1082.000000, 33.000000) rotate(180.000000) translate(-1082.000000, -33.000000) translate(1070.000000, 21.000000)">
<path d="M3.75,13.7454044 L7.96875,13.7454044 L7.96875,15.6204044 L3.75,15.6204044 L3.75,13.7454044 Z M3.75,11.8760807 L7.96875,11.8760807 L7.96875,10.0010807 L3.75,10.0010807 L3.75,11.8760807 Z M3.75,6.39170569 L3.75,8.26670569 L7.96875,8.26670569 L7.96875,6.39170569 L3.75,6.39170569 Z M3.75,19.2297794 L7.96875,19.2297794 L7.96875,17.3547794 L3.75,17.3547794 L3.75,19.2297794 Z M24,2.8125 L24,21.1875 C24,22.7384033 22.7384033,24 21.1875,24 L2.8125,24 C1.26159666,24 0,22.7384033 0,21.1875 L0,2.8125 C0,1.26159666 1.26159666,0 2.8125,0 L21.1875,0 C22.7384033,0 24,1.26159666 24,2.8125 Z M2.8125,22.125 L9.84375,22.125 L9.84375,1.875 L2.8125,1.875 C2.29559325,1.875 1.875,2.29559325 1.875,2.8125 L1.875,21.1875 C1.875,21.7044068 2.29559325,22.125 2.8125,22.125 Z M22.125,2.8125 C22.125,2.29559325 21.7044067,1.875 21.1875,1.875 L11.71875,1.875 L11.71875,10.921875 L16.7678833,10.921875 L14.6116333,8.765625 L15.9375,7.43975831 L20.3571167,11.859375 L15.9375,16.2789917 L14.6116333,14.953125 L16.7678833,12.796875 L11.71875,12.796875 L11.71875,22.125 L21.1875,22.125 C21.7044067,22.125 22.125,21.7044068 22.125,21.1875 L22.125,2.8125 Z" id="Shape" transform="translate(12.000000, 12.000000) scale(-1, 1) translate(-12.000000, -12.000000) "></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 59.1 (86144) - https://sketch.com -->
<title>show</title>
<desc>Created with Sketch.</desc>
<g id="Grading" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Grading-Copy-4" transform="translate(-1028.000000, -21.000000)" fill="#000000" fill-rule="nonzero">
<g id="show" transform="translate(1040.000000, 33.000000) rotate(180.000000) translate(-1040.000000, -33.000000) translate(1028.000000, 21.000000)">
<path d="M3.75,13.7454044 L7.96875,13.7454044 L7.96875,15.6204044 L3.75,15.6204044 L3.75,13.7454044 Z M3.75,11.8760807 L7.96875,11.8760807 L7.96875,10.0010807 L3.75,10.0010807 L3.75,11.8760807 Z M3.75,6.39170569 L3.75,8.26670569 L7.96875,8.26670569 L7.96875,6.39170569 L3.75,6.39170569 Z M3.75,19.2297794 L7.96875,19.2297794 L7.96875,17.3547794 L3.75,17.3547794 L3.75,19.2297794 Z M24,2.8125 L24,21.1875 C24,22.7384033 22.7384033,24 21.1875,24 L2.8125,24 C1.26159666,24 0,22.7384033 0,21.1875 L0,2.8125 C0,1.26159666 1.26159666,0 2.8125,0 L21.1875,0 C22.7384033,0 24,1.26159666 24,2.8125 Z M2.8125,22.125 L9.84375,22.125 L9.84375,1.875 L2.8125,1.875 C2.29559325,1.875 1.875,2.29559325 1.875,2.8125 L1.875,21.1875 C1.875,21.7044068 2.29559325,22.125 2.8125,22.125 Z M22.125,2.8125 C22.125,2.29559325 21.7044067,1.875 21.1875,1.875 L11.71875,1.875 L11.71875,10.921875 L16.7678833,10.921875 L14.6116333,8.765625 L15.9375,7.43975831 L20.3571167,11.859375 L15.9375,16.2789917 L14.6116333,14.953125 L16.7678833,12.796875 L11.71875,12.796875 L11.71875,22.125 L21.1875,22.125 C21.7044067,22.125 22.125,21.7044068 22.125,21.1875 L22.125,2.8125 Z" id="Shape"></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -49,29 +49,37 @@
{{{groupchangemenu}}}
{{#forum.capabilities.create}}
<div class="p-t-1 p-b-1">
<div class="p-t-1 p-b-1">
{{#forum.capabilities.create}}
<a class="btn btn-primary" data-toggle="collapse" href="#collapseAddForm">
{{$discussion_create_text}}
{{#str}}addanewdiscussion, forum{{/str}}
{{/discussion_create_text}}
</a>
<div class="collapse m-t-1" id="collapseAddForm">
{{{newdiscussionhtml}}}
</div>
{{/forum.capabilities.create}}
{{^forum.capabilities.create}}
{{#forum.capabilities.selfenrol}}
<div class="p-t-1 p-b-1">
<a class="btn btn-primary" href="{{forum.urls.create}}">
{{$discussion_create_text}}
{{#str}}addanewdiscussion, forum{{/str}}
{{/discussion_create_text}}
</a>
</div>
{{/forum.capabilities.selfenrol}}
{{/forum.capabilities.create}}
{{#forum.capabilities.grade}}
{{#forum.state.gradingenabled}}
{{> mod_forum/grades/grade_button }}
{{/forum.state.gradingenabled}}
{{/forum.capabilities.grade}}
</div>
{{#forum.capabilities.create}}
<div class="collapse m-t-1 p-b-1" id="collapseAddForm">
{{{newdiscussionhtml}}}
</div>
{{/forum.capabilities.create}}
{{^forum.capabilities.create}}
{{#forum.capabilities.selfenrol}}
<div class="p-t-1 p-b-1">
<a class="btn btn-primary" href="{{forum.urls.create}}">
{{$discussion_create_text}}
{{#str}}addanewdiscussion, forum{{/str}}
{{/discussion_create_text}}
</a>
</div>
{{/forum.capabilities.selfenrol}}
{{/forum.capabilities.create}}
{{#state.hasdiscussions}}
{{$discussion_top_pagination}}
@ -353,8 +361,4 @@
var root = $('#discussion-list-{{uniqid}}');
View.init(root);
});
require(['mod_forum/grades/grader'], function(Grader) {
Grader.registerLaunchListeners();
});
{{/js}}

View File

@ -47,7 +47,7 @@
>
{{#isfirstunread}}<a id="unread" aria-hidden="true"></a>{{/isfirstunread}}
<div class="author-image-container d-inline-block">
<div class="author-image-container d-inline-block text-center">
{{^isdeleted}}
{{#author}}
{{#urls.profileimage}}
@ -73,7 +73,7 @@
{{/unread}}
</div>
<div class="d-flex flex-column w-100" data-region-content="forum-post-core">
<div class="forum-post-core d-flex flex-column w-100" data-region-content="forum-post-core">
<header id="post-header-{{uniqid}}">
{{^isdeleted}}
<div class="d-flex flex-wrap align-items-center mb-1">
@ -299,9 +299,11 @@
{{/attachments}}
<div class="d-flex mt-3 align-items-center">
{{#html.rating}}
<div>{{{.}}}</div>
{{/html.rating}}
{{^readonly}}
{{#html.rating}}
<div>{{{.}}}</div>
{{/html.rating}}
{{/readonly}}
<div class="ml-auto d-flex flex-column">
{{#haswordcount}}
<span class="ml-auto badge badge-light">

View File

@ -179,12 +179,12 @@
{{/isimage}}
{{/attachments}}
<div class="d-flex flex-wrap">
{{#html.rating}}
<div class="mt-2">{{{.}}}</div>
{{/html.rating}}
{{$actions}}
{{^readonly}}
{{^readonly}}
<div class="d-flex flex-wrap">
{{#html.rating}}
<div class="mt-2">{{{.}}}</div>
{{/html.rating}}
{{$actions}}
<div
class="post-actions d-flex align-self-end justify-content-end flex-wrap ml-auto"
data-region="post-actions-container"
@ -303,9 +303,9 @@
{{/export}}
{{/capabilities}}
</div>
{{/readonly}}
{{/actions}}
</div>
{{/actions}}
</div>
{{/readonly}}
{{$footer}}{{/footer}}
{{/isdeleted}}

View File

@ -29,13 +29,25 @@
{
}
}}
<a class="btn btn-primary" href="" data-grade-action="launch" {{!
}}data-contextid="{{contextid}}" {{!
}}data-cmid="{{cmid}}" {{!
}}data-name="{{name}}" {{!
}}data-group="{{groupid}}" {{!
}}data-grading-component="{{gradingcomponent}}" {{!
}}data-grading-component-subtype="{{gradingcomponentsubtype}}" {{!
}}data-gradable-itemtype="forum" {{!
}}{{#firstgradeduserid}}data-initialuserid="{{firstgradeduserid}}" {{/firstgradeduserid}}{{!
}}>{{#str}}gradeusers, forum{{/str}}</a>
<button
class="btn btn-secondary"
type="button"
data-grade-action="launch"
data-contextid="{{contextid}}"
data-cmid="{{cmid}}"
data-name="{{name}}"
data-course-id="{{courseid}}"
data-course-name="{{coursename}}"
data-experimental-display-mode="{{experimentaldisplaymode}}"
data-group="{{groupid}}"
data-grading-component="{{gradingcomponent}}"
data-grading-component-subtype="{{gradingcomponentsubtype}}"
data-gradable-itemtype="forum"
>
{{#str}}gradeusers, forum{{/str}}
</button>
{{#js}}
require(['mod_forum/grades/grader'], function(Grader) {
Grader.registerLaunchListeners();
});
{{/js}}

View File

@ -29,8 +29,9 @@
{
}
}}
<div data-region="posts-modal">
{{#.}}
{{> mod_forum/forum_discussion_nested_v2_post_reply }}
{{/.}}
<div class="{{#experimentaldisplaymode}}nested-v2-display-mode{{/experimentaldisplaymode}}" data-region="posts-modal">
{{#posts}}
{{#experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_v2_first_post }}{{/experimentaldisplaymode}}
{{^experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_post }}{{/experimentaldisplaymode}}
{{/posts}}
</div>

View File

@ -29,48 +29,68 @@
{
}
}}
<div data-region="posts" id="post-region-{{uniqid}}">
<div
class="{{#experimentaldisplaymode}}nested-v2-display-mode{{/experimentaldisplaymode}}"
data-region="posts"
id="post-region-{{uniqid}}"
>
{{#discussions}}
<div class="hr-sect mt-0">{{name}}</div>
{{#posts}}
{{#parent}}
{{> mod_forum/forum_discussion_nested_v2_post_reply }}
{{/parent}}
{{#starter}}
{{> mod_forum/forum_discussion_nested_v2_first_post }}
<a class="btn btn-outline-dark"
role="button"
data-action="view-context"
data-discussionid="{{discussionid}}"
data-postid="{{id}}"
data-name="{{name}}"
href="#">
{{#str}} viewconversation, forum {{/str}}
</a>
{{/starter}}
{{^starter}}
<div class="forum-post-container" data-region="replies-container">
<div class="indent replies-container" data-region="replies-container">
<div class="indent replies-container" data-region="replies-container">
{{> mod_forum/forum_discussion_nested_v2_post_reply }}
<a class="btn btn-outline-dark"
role="button"
data-action="view-context"
data-discussionid="{{discussionid}}"
data-postid="{{id}}"
data-name="{{name}}"
href="#">
<div class="discussion-container">
<div class="p-4">
<h3 class="d-inline-block m-0 h6 font-weight-bold">{{#str}} discussionstartedby, mod_forum, {{authorfullname}} {{/str}}</h3>
<p class="d-inline-block m-0 h6 font-weight-normal text-muted ml-1">
{{#userdate}} {{timecreated}}, {{#str}} strftimedate, core_langconfig {{/str}} {{/userdate}}
</p>
<h2 class="mb-4 font-weight-bold">{{name}}</h2>
{{#posts}}
<div class="posts-container">
{{#parent}}
<div class="parent-container">
<button
class="btn btn-link show-content-button collapsed"
data-target="#parent-post-content-{{id}}"
aria-expanded="false"
aria-controls="parent-post-content-{{id}}"
data-toggle="collapse"
>
{{#str}} viewparentpost, mod_forum {{/str}}
</button>
<div id="parent-post-content-{{id}}" class="content collapse">
{{#experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_v2_first_post }}{{/experimentaldisplaymode}}
{{^experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_post }}{{/experimentaldisplaymode}}
</div>
</div>
{{/parent}}
{{#post}}
<div class="post-container">
{{#experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_v2_first_post }}{{/experimentaldisplaymode}}
{{^experimentaldisplaymode}}{{> mod_forum/forum_discussion_nested_post }}{{/experimentaldisplaymode}}
</div>
<button
class="view-context-button btn btn-link border"
type="button"
data-action="view-context"
data-discussionid="{{discussionid}}"
data-postid="{{id}}"
data-name="{{name}}"
data-experimental-display-mode="{{experimentaldisplaymode}}"
>
{{#str}} viewconversation, forum {{/str}}
</a>
</div>
</button>
{{/post}}
<hr class="w-75 mx-auto my-5">
</div>
</div>
{{/starter}}
{{/posts}}
</div>
<hr>
{{/posts}}
</div>
{{/discussions}}
{{^discussions}}
<h3>{{#str}} noposts, forum {{/str}}</h3>
<div class="no-post-container text-center p-5">
{{#pix}} no-posts, mod_forum {{/pix}}
<h2 class="mt-3 font-weight-bold">{{#str}} noposts, mod_forum {{/str}}</h2>
</div>
{{/discussions}}
</div>
{{#js}}

View File

@ -34,16 +34,41 @@
"cmid": 1337
}
}}
<div class="container-fluid"
<div
id="grader-container-{{uniqid}}"
class="d-flex flex-column h-100 unified-grader"
data-region="unified-grader"
{{#userid}}data-first-userid="{{userid}}"{{/userid}}
{{#userid}}data-first-userid="{{.}}"{{/userid}}
data-cmid="{{cmid}}"
>
<div class="row-fluid">
{{> mod_forum/local/grades/local/grader/navigation }}
</div>
<div class="row-fluid no-gutters">
>
{{> mod_forum/local/grades/local/grader/navigation }}
<div class="d-flex flex-grow-1 h-100 position-relative">
{{#drawer}}{{> mod_forum/local/grades/local/grader/grading }}{{/drawer}}
{{> mod_forum/local/grades/local/grader/content }}
{{> mod_forum/local/grades/local/grader/grading }}
</div>
</div>
{{#js}}
require(['jquery', 'core/drawer'], function($, Drawer) {
var root = $('#grader-container-{{uniqid}}');
var drawer = root.find('[data-region="right-hand-drawer"]');
var expandButtons = root.find('[data-action="expand-grading-drawer"]');
var collapseButtons = root.find('[data-action="collapse-grading-drawer"]');
expandButtons.click(function() {
collapseButtons.removeClass('active');
expandButtons.addClass('active');
collapseButtons.attr('aria-expanded', true);
expandButtons.attr('aria-expanded', true);
Drawer.show(drawer);
});
collapseButtons.click(function() {
expandButtons.removeClass('active');
collapseButtons.addClass('active');
collapseButtons.attr('aria-expanded', false);
expandButtons.attr('aria-expanded', false);
Drawer.hide(drawer);
});
});
{{/js}}

View File

@ -30,6 +30,8 @@
{
}
}}
<div class="grader-module-content col-sm-12 col-md-8 mb-3">
<div data-region="module_content" class="grader-module-content-display col-sm-12"></div>
<div class="grader-module-content w-100 h-100">
<div data-region="module_content" class="grader-module-content-display">
{{> mod_forum/local/grades/local/grader/module_content_placeholder }}
</div>
</div>

View File

@ -30,14 +30,227 @@
{
}
}}
<div class="bg-pulse-grey w-25" style="height: 20px;"></div>
<div class="bg-pulse-grey w-50 mt-1" style="height: 25px;"></div>
<div class="bg-pulse-grey w-25 mt-3" style="height: 20px;"></div>
<div class="bg-pulse-grey w-50 mt-1" style="height: 25px;"></div>
<div class="bg-pulse-grey w-25 mt-3" style="height: 20px;"></div>
<div class="bg-pulse-grey w-100 mt-1" style="height: 25px;"></div>
<div class="bg-pulse-grey w-25 mt-3" style="height: 20px;"></div>
<div class="bg-pulse-grey w-100 mt-1" style="height: 25px;"></div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>
<div class="d-flex flex-column mb-3">
<div class="d-flex align-items-center mb-2" style="height: 36px">
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto mr-2" style="height: 16px; width: 16px"></div>
</div>
<div class="d-flex flex-column">
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div class="d-flex align-items-center mb-2" style="height: 22px">
<div class="bg-pulse-grey rounded-circle mr-1" style="height: 16px; width: 16px"></div>
<div class="bg-pulse-grey" style="height: 19px; width: 100px"></div>
<div class="bg-pulse-grey ml-auto" style="height: 19px; width: 50px"></div>
</div>
<div>
<div class="bg-pulse-grey mb-2" style="height: 22px; width: 150px"></div>
<div class="bg-pulse-grey" style="height: 36px; width: 100%"></div>
</div>
</div>
</div>

View File

@ -32,24 +32,76 @@
{
}
}}
<div class="grader-grading-panel border-left border-secondary col-md-4">
<div class="col-md-12 bg-light px-2 py-3 mb-3">
<!--TODO Manipulate grader panel-->
<h4 class="d-inline font-weight-bold mb-0 fa fa-arrow-right" aria-label="Open or close grader panel" data-action="expandgrader"></h4>
<h4 class="d-inline font-weight-bold mb-0">{{#str}}grading, mod_forum{{/str}}</h4>
</div>
<div data-region="user_picker">
{{> mod_forum/local/grades/local/grader/user_picker_placeholder }}
<hr/>
</div>
<div class="grader-grading-panel-display col-sm-12">
<h4 class="d-inline mb-0 fa fa-star-o"></h4>
<h4 class="d-inline mb-0 ">{{#str}}grade, core_grades{{/str}}</h4>
<div data-region="grade" class="col-md-12 mt-3">
{{> mod_forum/local/grades/local/grader/grade_placeholder }}
{{<core/drawer}}
{{$drawerclasses}}grader-grading-panel flex-shrink-0{{/drawerclasses}}
{{$drawercontent}}
<div class="h-100 w-100 bg-white d-flex flex-column">
<div class="flex-shrink-0 d-flex flex-column">
<div class="header-container bg-light">
<div
id="searchbox-{{uniqid}}"
class="user-search-container d-flex flex-grow-1 align-items-center collapsed"
data-region="user-search-container"
>
<div class="search-input-container w-100">
<span class="search-icon icon-no-margin d-flex align-items-center justify-content-center">
{{#pix}} i/search, core {{/pix}}
</span>
<input
type="text"
data-region="user-search-input"
class="form-control form-control-lg"
placeholder="{{#str}} searchusers, mod_forum {{/str}}"
>
<button
class="toggle-search-button btn btn-icon icon-no-margin"
aria-expanded="false"
aria-controls="searchbox-{{uniqid}}"
data-action="toggle-search"
>
<div class="expanded-icon">
<span aria-hidden="true">{{#pix}} e/cancel, core, {{#str}} hideusersearch, mod_forum {{/str}} {{/pix}}</span>
<span class="sr-only">{{#str}} hideusersearch, mod_forum {{/str}}</span>
</div>
<div class="collapsed-icon">
<span aria-hidden="true">{{#pix}} i/search, core, {{#str}} showusersearch, mod_forum {{/str}} {{/pix}}</span>
<span class="sr-only">{{#str}} showusersearch, mod_forum {{/str}}</span>
</div>
</button>
</div>
</div>
<div class="info-container d-flex align-items-center">
<button
class="btn btn-icon icon-size-3 icon-no-margin colour-inherit"
data-action="collapse-grading-drawer"
aria-controls="grading-drawer"
aria-expanded="true"
title="{{#str}} closebuttontitle, core {{/str}}"
>
<span class="dir-ltr-hide">{{#pix}} t/left, core {{/pix}}</span>
<span class="dir-rtl-hide">{{#pix}} t/right, core {{/pix}}</span>
</button>
<div class="ml-auto mr-auto text-center" data-region="status-container">
{{> mod_forum/local/grades/local/grader/status_placeholder }}
</div>
</div>
</div>
<div class="border-bottom px-3 pt-2" data-region="user_picker">
{{> mod_forum/local/grades/local/grader/user_picker_placeholder }}
</div>
</div>
<div class="body-container position-relative d-flex flex-column overflow-auto" data-region="body-container">
<div class="grader-grading-panel-display pt-3 overflow-auto" data-region="grading-panel-container">
<h4 class="mb-0 h5 px-3 font-weight-normal">
{{#pix}} i/grading, core {{/pix}}{{#str}} gradingmodulename, core_grades, {{moduleName}} {{/str}}
</h4>
<div data-region="grade" class="pt-3 px-3">
{{> mod_forum/local/grades/local/grader/grade_placeholder }}
</div>
<div data-region="grade-errors" role="alert" aria-role="assertive"></div>
</div>
</div>
<div class="hidden overflow-auto" data-region="search-results-container"></div>
</div>
<div data-region="grade-errors" role="alert" aria-role="assertive"></div>
<hr/>
</div>
</div>
{{/drawercontent}}
{{/core/drawer}}

View File

@ -0,0 +1,170 @@
{{!
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 mod_forum/local/grades/local/grader/module_content_placeholder
Classes required for JS:
* none
Data attributes required for JS:
*
Context variables required for this template:
*
Example context (json):
{}
}}
<div class="p-4">
<div class="d-inline-block bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="d-inline-block bg-pulse-grey ml-1 mb-1" style="height: 18px; width: 100px"></div>
<div class="bg-pulse-grey mb-4" style="height: 36px; width: 500px"></div>
<div class="d-flex align-items-center mb-2 p-2" style="height: 63px">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="bg-pulse-grey" style="height: 15px; width: 150px"></div>
</div>
<div class="mb-2 p-2">
<div class="d-flex mb-2">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="mb-3">
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 350px"></div>
</div>
</div>
<div class="d-flex w-100">
<div class="flex-shrink-0 mr-2" style="height: 45px; width: 45px"></div>
<div class="flex-grow-1">
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 95%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 97%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 93%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 75%"></div>
</div>
</div>
</div>
<div class="bg-pulse-grey" style="height: 36px; width: 150px"></div>
<hr class="w-75 mx-auto my-5">
<div class="d-flex align-items-center mb-2 p-2" style="height: 63px">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="bg-pulse-grey" style="height: 15px; width: 150px"></div>
</div>
<div class="mb-2 p-2">
<div class="d-flex mb-2">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="mb-3">
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 350px"></div>
</div>
</div>
<div class="d-flex w-100">
<div class="flex-shrink-0 mr-2" style="height: 45px; width: 45px"></div>
<div class="flex-grow-1">
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 95%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 97%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 93%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 75%"></div>
</div>
</div>
</div>
<div class="bg-pulse-grey" style="height: 36px; width: 150px"></div>
<hr class="w-75 mx-auto my-5">
<div class="d-flex align-items-center mb-2 p-2" style="height: 63px">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="bg-pulse-grey" style="height: 15px; width: 150px"></div>
</div>
<div class="mb-2 p-2">
<div class="d-flex mb-2">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="mb-3">
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 350px"></div>
</div>
</div>
<div class="d-flex w-100">
<div class="flex-shrink-0 mr-2" style="height: 45px; width: 45px"></div>
<div class="flex-grow-1">
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 95%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 97%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 93%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 75%"></div>
</div>
</div>
</div>
<div class="bg-pulse-grey" style="height: 36px; width: 150px"></div>
<hr class="w-75 mx-auto my-5">
<div class="d-flex align-items-center mb-2 p-2" style="height: 63px">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="bg-pulse-grey" style="height: 15px; width: 150px"></div>
</div>
<div class="mb-2 p-2">
<div class="d-flex mb-2">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="mb-3">
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 350px"></div>
</div>
</div>
<div class="d-flex w-100">
<div class="flex-shrink-0 mr-2" style="height: 45px; width: 45px"></div>
<div class="flex-grow-1">
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 95%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 97%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 93%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 75%"></div>
</div>
</div>
</div>
<div class="bg-pulse-grey" style="height: 36px; width: 150px"></div>
<hr class="w-75 mx-auto my-5">
<div class="d-flex align-items-center mb-2 p-2" style="height: 63px">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="bg-pulse-grey" style="height: 15px; width: 150px"></div>
</div>
<div class="mb-2 p-2">
<div class="d-flex mb-2">
<div class="bg-pulse-grey rounded-circle mr-2" style="height: 45px; width: 45px"></div>
<div class="mb-3">
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 200px"></div>
<div class="bg-pulse-grey mb-1" style="height: 18px; width: 350px"></div>
</div>
</div>
<div class="d-flex w-100">
<div class="flex-shrink-0 mr-2" style="height: 45px; width: 45px"></div>
<div class="flex-grow-1">
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 95%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 97%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 93%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 100%"></div>
<div class="bg-pulse-grey mb-1" style="height: 15px; width: 75%"></div>
</div>
</div>
</div>
<div class="bg-pulse-grey" style="height: 36px; width: 150px"></div>
</div>

View File

@ -34,27 +34,78 @@
"moduleName": "Chef the Forum"
}
}}
<div class="grader-grading_navigation col-sm-12">
<div class="row">
<div class="col-sm-12 col-md-8 py-3">
<div class="d-block">
<h6 class="d-inline btn px-0 font-weight-bold text-muted mb-0">{{moduleName}}</h6>
<h6 class="d-inline btn px-0 font-weight-bold text-muted mb-0"> > </h6>
<h6 class="d-inline btn px-0 font-weight-bold mb-0">{{#str}}grading, forum{{/str}}</h6>
<nav id="nav-container-{{uniqid}}" class="grader-grading_navigation navbar">
<div class="d-none d-sm-flex align-items-center">
<a href="{{{courseUrl}}}" class="btn btn-link px-2 colour-inherit">
<h5 class="d-inline px-0 mb-0">{{courseName}}</h5>
</a>
<span class="text-muted icon-no-margin">{{#pix}} i/breadcrumbdivider, core {{/pix}}</span>
<button class="btn btn-link px-2 colour-inherit" data-action="closegrader">
<h5 class="d-inline px-0 mb-0">{{moduleName}}</h5>
</button>
<span class="text-muted icon-no-margin">{{#pix}} i/breadcrumbdivider, core {{/pix}}</span>
<h5 class="d-inline px-2 mb-0 font-weight-bold">{{#str}}grading, forum{{/str}}</h5>
</div>
<div class="ml-auto">
<button
class="btn btn-icon icon-no-margin drawer-button mr-1 active"
data-action="expand-grading-drawer"
aria-controls="grading-drawer"
aria-expanded="true"
type="button"
title="{{#str}} showgraderpanel, mod_forum {{/str}}"
>
<span class="dir-ltr-hide" aria-hidden="true">{{#pix}} show-grader-panel-rtl, mod_forum, {{#str}} showgraderpanel, mod_forum {{/str}} {{/pix}}</span>
<span class="dir-rtl-hide" aria-hidden="true">{{#pix}} show-grader-panel, mod_forum, {{#str}} showgraderpanel, mod_forum {{/str}} {{/pix}}</span>
</button>
<button
class="btn btn-icon icon-no-margin drawer-button mr-1"
aria-label="Open or close grader panel"
data-action="collapse-grading-drawer"
aria-controls="grading-drawer"
aria-expanded="true"
type="button"
title="{{#str}} hidegraderpanel, mod_forum {{/str}}"
>
<span aria-hidden="true">{{#pix}} hide-grader-panel, mod_forum, {{#str}} hidegraderpanel, mod_forum {{/str}} {{/pix}}</span>
</button>
<button
class="btn btn-primary font-weight-bold ml-2 px-4"
data-action="savegrade"
>
{{#str}} save {{/str}}
</button>
<button
class="btn btn-secondary font-weight-bold ml-2 px-4"
aria-label="{{#str}} closegrader, mod_forum {{/str}}"
data-action="closegrader"
type="button"
>
{{#str}} close, mod_forum {{/str}}
</button>
<div class="btn-group">
<button
class="btn btn-icon text-muted icon-no-margin icon-size-3 ml-2"
type="button"
id="grader-actions-menu-{{uniqid}}"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
aria-label="{{#str}} actionsforgraderinterface, mod_forum {{/str}}"
>
{{#pix}} i/menu, core {{/pix}}
</button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="grader-actions-menu-{{uniqid}}">
<button
class="dropdown-item"
type="button"
data-action="togglefullscreen"
type="button"
>
{{#str}} togglefullscreen, mod_forum {{/str}}
</button>
</div>
</div>
<div class="col-sm-12 col-md-4 py-3">
<a href="#" class="btn fa fa-arrows-alt float-right" aria-label="Toggle fullscreen" data-action="togglefullscreen"></a>
<a href="#" class="btn btn-secondary float-right" aria-label="Close grade interface" data-action="closegrader">Close</a>
<a href="#" role="button" class="btn btn-primary float-right" aria-label="Save and quit" data-action="savegrade">Save</a>
<!--TODO Manipulate grader panel see also Grading panel-->
<a href="#" role="button" class="btn fa fa-check-circle float-right" aria-label="Open or close grader panel" data-action="expandgrader"></a>
</div>
</div>
</div>
</nav>

View File

@ -0,0 +1,37 @@
{{!
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 mod_forum/local/grades/local/grader/status
Classes required for JS:
* none
Data attributes required for JS:
*
Context variables required for this template:
*
Example context (json):
{
"status": "Graded",
"index": 1,
"total": 10
}
}}
{{#status}}<h2 class="font-weight-bold h5 mb-0">{{.}}</h2>{{/status}}
<div>{{#str}} indexoutoftotal, mod_forum, {"index": "{{index}}", "total":"{{total}}"}{{/str}}</div>

View File

@ -0,0 +1,33 @@
{{!
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 mod_forum/local/grades/local/grader/status_placeholder
Classes required for JS:
* none
Data attributes required for JS:
*
Context variables required for this template:
*
Example context (json):
{}
}}
<div class="bg-pulse-grey mb-1" style="height: 22px; width: 75px"></div>
<div class="bg-pulse-grey ml-auto mr-auto" style="height: 19px; width: 60px"></div>

View File

@ -34,40 +34,39 @@
{
}
}}
<div class="col-md-12">
<div class="row">
<div class="col-md-8">
<div data-region="user_picker/user"></div>
</div>
<div class="col-md-4">
<ul class="pagination">
<li class="page-item mr-3">
<a class="page-link" href="#" aria-label="Previous" data-action="change-user" data-direction="-1">
<span aria-hidden="true">&langle;</span>
<span class="sr-only">{{#str}} previous {{/str}}</span>
</a>
</li>
<li class="page-item mr-3">
<a class="page-link" href="#" aria-label="Next" data-action="change-user" data-direction="1">
<span aria-hidden="true">&rangle;</span>
<span class="sr-only">{{#str}} next {{/str}}</span>
</a>
</li>
<li>
<button class="btn btn-icon icon-size-4 icon-no-margin colour-inherit" aria-label="{{#str}} search {{/str}}" data-target="#searchbox" aria-expanded="false" aria-controls="searchbox" data-toggle="collapse">
<i class="icon fa fa-search fa-fw" aria-hidden="true"></i>
<span class="sr-only">{{#str}} search {{/str}}</span>
</button>
</li>
<div class="d-flex align-items-center user-picker-container mb-2 py-2">
<div class="d-flex align-items-center" data-region="user_picker/user"></div>
<div class="ml-auto flex-shrink-0">
<nav aria-label="{{#str}} usernavigation, mod_forum {{/str}}">
<ul class="pagination mb-0">
<li class="page-item">
<a
class="page-link icon-no-margin p-0 text-reset icon-size-3"
href="#"
aria-label="{{#str}} previous {{/str}}"
data-action="change-user"
data-direction="-1"
title="{{#str}} previoususer, mod_forum {{/str}}"
>
<span class="dir-ltr-hide">{{#pix}} i/next, core {{/pix}}</span>
<span class="dir-rtl-hide">{{#pix}} i/previous, core {{/pix}}</span>
</a>
</li>
<li class="page-item">
<a
class="page-link icon-no-margin p-0 text-reset icon-size-3 ml-2"
href="#"
aria-label="{{#str}} next {{/str}}"
data-action="change-user"
data-direction="1"
title="{{#str}} nextuser, mod_forum {{/str}}"
>
<span class="dir-ltr-hide">{{#pix}} i/previous, core {{/pix}}</span>
<span class="dir-rtl-hide">{{#pix}} i/next, core {{/pix}}</span>
</a>
</li>
</ul>
</div>
<div id="searchbox" class="col-md-12 collapse">
<form action="" class="search-form my-3 w-100">
<input type="text" data-action="search-user-input" class="form-control input-lg" placeholder="Search user">
</form>
<div data-action="search-user-box"></div>
</div>
</nav>
</div>
<hr>
</div>

View File

@ -38,5 +38,21 @@
"total": 7
}
}}
<div class="d-block font-weight-bold" data-region="name" data-userid="{{id}}">{{fullname}}</div>
<div class="d-block"><div class="d-inline" data-region="index">{{displayIndex}}</div>/{{total}}</div>
{{#profileimage}}
<img
class="rounded-circle userpicture mr-2"
src="{{.}}"
alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
>
{{/profileimage}}
<div>
<h5
class="mb-0 font-weight-bold user-full-name text-truncate"
data-region="name"
data-userid="{{id}}"
>
{{fullname}}
</h5>
</div>

View File

@ -56,40 +56,20 @@
]
}
}}
<div data-action="search-user-box">
{{#expandedUsers}}
<div class="mt-2">
<img class="rounded-circle userpicture" src="{{profileimage}}"
alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{fullname}}{{/str}}" >
<a href="#" class="font-weight-bold" data-action="select-user" data-userid="{{id}}">{{fullname}}</a>
</div>
{{/expandedUsers}}
{{^expandedUsers}}
<h5>{{#str}}nousersmatch, mod_forum{{/str}}</h5>
{{/expandedUsers}}
{{#hasCollapsed}}
<div class="d-flex flex-column px-3 py-2" data-action="search-user-box">
{{#users}}
<button
class="btn btn-icon mt-2 text-muted icon-no-margin icon-size-3"
type="button"
id="grader-users-menu-{{uniqid}}"
aria-label="{{#str}} showmoreusers, mod_forum {{/str}}"
data-toggle="collapse"
data-target="#collapsed-users-{{uniqid}}"
aria-expanded="false"
aria-controls="collapsed-users-{{uniqid}}"
class="btn btn-link text-reset p-0 mb-2 d-flex align-items-center"
data-action="select-user"
data-userid="{{id}}"
>
{{#pix}} i/moremenu {{/pix}}
{{> mod_forum/local/grades/local/grader/user_picker/user }}
</button>
<div id="collapsed-users-{{uniqid}}" class="collapse" aria-labelledby="grader-users-menu-{{uniqid}}">
{{#collapsedUsers}}
<div class="mt-2">
<img class="rounded-circle userpicture" src="{{profileimage}}"
alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{fullname}}{{/str}}" >
<a href="#" class="font-weight-bold" data-action="select-user" data-userid="{{id}}">{{fullname}}</a>
</div>
{{/collapsedUsers}}
{{/users}}
{{^users}}
<div class="no-search-results-container text-center">
{{#pix}} no-search-results, mod_forum {{/pix}}
<h5 class="font-weight-bold mt-3">{{#str}}nousersmatch, mod_forum{{/str}}</h5>
</div>
{{/hasCollapsed}}
{{/users}}
</div>

View File

@ -30,29 +30,21 @@
{
}
}}
<div class="col-md-12 mt-3">
<div class="row">
<div class="col-md-8">
<div class="bg-pulse-grey w-50" style="height: 20px;"></div>
<div class="bg-pulse-grey w-25 mt-1" style="height: 15px;"></div>
</div>
<div class="col-md-4">
<ul class="pagination">
<li class="page-item mr-3">
<span class="btn bg-pulse-grey" aria-hidden="true">&langle;</span>
<span class="sr-only">{{#str}} previous {{/str}}</span>
</li>
<li class="page-item mr-3">
<span class="btn bg-pulse-grey" aria-hidden="true">&rangle;</span>
<span class="sr-only">{{#str}} next {{/str}}</span>
<div class="d-flex align-items-center user-picker-container mb-2 py-2">
<div class="d-flex align-items-center">
<div class="bg-pulse-grey rounded-circle d-inline-block flex-shrink-0 userpicture mr-2"></div>
<div class="bg-pulse-grey d-inline-block" style="height: 22px; width: 150px"></div>
</div>
<div class="ml-auto flex-shrink-0">
<nav>
<ul class="pagination mb-0">
<li class="page-item">
<a class="bg-pulse-grey border-0 page-link icon-no-margin p-0 icon-size-3" href="#"></a>
</li>
<li class="page-item">
<span class="btn bg-pulse-grey fa fa-search" aria-hidden="true"></span>
<span class="sr-only">{{#str}} search {{/str}}</span>
<a class="bg-pulse-grey border-0 page-link icon-no-margin p-0 icon-size-3 ml-2" href="#"></a>
</li>
</ul>
</div>
</nav>
</div>
</div>

View File

@ -2664,17 +2664,21 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
$record->course = $course1->id;
$record->userid = $user1->id;
$record->forum = $forum1->id;
$record->timemodified = 1;
$discussion1 = $forumgenerator->create_discussion($record);
$discussion1firstpost = $postvault->get_first_post_for_discussion_ids([$discussion1->id]);
$discussion1firstpostobject = $legacypostmapper->to_legacy_object($discussion1firstpost[$discussion1->firstpost]);
$discussion1firstpost = $discussion1firstpost[$discussion1->firstpost];
$discussion1firstpostobject = $legacypostmapper->to_legacy_object($discussion1firstpost);
$record = new stdClass();
$record->course = $course1->id;
$record->userid = $user1->id;
$record->forum = $forum1->id;
$record->timemodified = 2;
$discussion2 = $forumgenerator->create_discussion($record);
$discussion2firstpost = $postvault->get_first_post_for_discussion_ids([$discussion2->id]);
$discussion2firstpostobject = $legacypostmapper->to_legacy_object($discussion2firstpost[$discussion2->firstpost]);
$discussion2firstpost = $discussion2firstpost[$discussion2->firstpost];
$discussion2firstpostobject = $legacypostmapper->to_legacy_object($discussion2firstpost);
// Add 1 reply to the discussion 1 from a different user.
$record = new stdClass();
@ -2733,6 +2737,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
$expectedposts['discussions'][0] = [
'name' => $discussion1->name,
'id' => $discussion1->id,
'timecreated' => $discussion1firstpost->get_time_created(),
'authorfullname' => $user1entity->get_full_name(),
'posts' => [
'userposts' => [
[
@ -2864,6 +2870,8 @@ class mod_forum_external_testcase extends externallib_advanced_testcase {
$expectedposts['discussions'][1] = [
'name' => $discussion2->name,
'id' => $discussion2->id,
'timecreated' => $discussion2firstpost->get_time_created(),
'authorfullname' => $user1entity->get_full_name(),
'posts' => [
'userposts' => [
[

View File

@ -105,25 +105,7 @@ $PAGE->set_context($forum->get_context());
$PAGE->set_title($forum->get_name());
$PAGE->add_body_class('forumtype-' . $forum->get_type());
$PAGE->set_heading($course->fullname);
$buttons = [];
if ($capabilitymanager->can_grade($USER)) {
$forumgradeitem = forum_gradeitem::load_from_forum_entity($forum);
if ($forumgradeitem->is_grading_enabled()) {
$groupid = groups_get_activity_group($cm, true) ?: null;
$gradeobj = (object) [
'contextid' => $forum->get_context()->id,
'cmid' => $cmid,
'name' => $forum->get_name(),
'groupid' => $groupid,
'gradingcomponent' => $forumgradeitem->get_grading_component_name(),
'gradingcomponentsubtype' => $forumgradeitem->get_grading_component_subtype(),
];
$buttons[] = $OUTPUT->render_from_template('mod_forum/grades/grade_button', $gradeobj);
}
}
$buttons[] = forum_search_form($course, $search);
$PAGE->set_button(implode('', $buttons));
$PAGE->set_button(forum_search_form($course, $search));
if ($istypesingle && $displaymode == FORUM_MODE_NESTED_V2) {
$PAGE->add_body_class('reset-style');
@ -189,6 +171,24 @@ $groupid = groups_get_activity_group($cm, true) ?: null;
$rendererfactory = mod_forum\local\container::get_renderer_factory();
switch ($forum->get_type()) {
case 'single':
if ($capabilitymanager->can_grade($USER)) {
$forumgradeitem = forum_gradeitem::load_from_forum_entity($forum);
if ($forumgradeitem->is_grading_enabled()) {
$groupid = groups_get_activity_group($cm, true) ?: null;
$gradeobj = (object) [
'contextid' => $forum->get_context()->id,
'cmid' => $cmid,
'name' => $forum->get_name(),
'courseid' => $course->id,
'coursename' => $course->shortname,
'experimentaldisplaymode' => $displaymode == FORUM_MODE_NESTED_V2,
'groupid' => $groupid,
'gradingcomponent' => $forumgradeitem->get_grading_component_name(),
'gradingcomponentsubtype' => $forumgradeitem->get_grading_component_subtype(),
];
echo $OUTPUT->render_from_template('mod_forum/grades/grade_button', $gradeobj);
}
}
$discussion = $discussionvault->get_last_discussion_in_forum($forum);
$discussioncount = $discussionvault->get_count_discussions_in_forum($forum);
$hasmultiplediscussions = $discussioncount > 1;
@ -227,7 +227,7 @@ switch ($forum->get_type()) {
break;
default:
$discussionsrenderer = $rendererfactory->get_discussion_list_renderer($forum);
echo $discussionsrenderer->render($USER, $cm, $groupid, $sortorder, $pageno, $pagesize);
echo $discussionsrenderer->render($USER, $cm, $groupid, $sortorder, $pageno, $pagesize, $displaymode);
}
echo $OUTPUT->footer();

View File

@ -366,6 +366,7 @@ select[size="1"] {
textarea[data-auto-rows] {
overflow-x: hidden;
resize: none;
}
/** Display elements under labels in vertical forms regardless of the screen size. */

View File

@ -240,20 +240,30 @@
}
}
.criterion button.collapse[aria-expanded="true"]:before {
content: $fa-var-angle-down;
margin-right: 0;
@include fa-icon();
font-size: 16px;
width: 16px;
}
.criterion {
.description {
font-size: 1rem;
}
.criterion button.collapse[aria-expanded="false"]:before {
content: $fa-var-angle-up;
margin-right: 0;
@include fa-icon();
font-size: 16px;
width: 16px;
.criterion-toggle {
.expanded-icon {
display: block;
}
.collapsed-icon {
display: none;
}
&.collapsed {
.expanded-icon {
display: none;
}
.collapsed-icon {
display: block;
}
}
}
}
// Set up grades layout.

View File

@ -1,17 +1,21 @@
.layout {
&.fullscreen {
height: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: $zindex-modal-backdrop;
overflow-x: hidden;
transition: 0.5s;
width: 100%;
width: 100vw;
margin: 0;
opacity: 1;
background-color: $modal-content-bg;
> div {
height: 100%;
width: 100%;
}
.loading-icon {
margin-left: auto;
margin-right: auto;

View File

@ -218,7 +218,7 @@ $author-image-margin-sm: 8px;
}
}
#page-mod-forum-view [data-region="unified-grader"],
.path-mod-forum .nested-v2-display-mode,
.path-mod-forum.nested-v2-display-mode {
.discussionsubscription {
margin-top: 0;
@ -426,6 +426,492 @@ $author-image-margin-sm: 8px;
}
}
$grading-drawer-width: 430px !default;
$grading-animation-duration: .3s !default;
$grading-icon-button-size: 36px !default;
$grading-search-button-padding-left: calc(#{map-get($spacers, 2)} + 8px) !default;
$grading-search-input-padding-left: calc(#{map-get($spacers, 2)} + #{map-get($spacers, 2)} + #{$grading-icon-button-size - ($input-border-width * 2)}) !default; /* stylelint-disable-line max-line-length */
$grading-search-input-padding-right: calc(#{map-get($spacers, 2)} + #{$grading-icon-button-size}) !default;
$grading-nav-bar-active-drawer-button-bottom: calc(#{map-get($spacers, 2) * -1} - 1px) !default;
$grading-content-show-content-button-padding-left: calc(#{map-get($spacers, 2) * 2} + 45px) !default;
@keyframes expandSearchButton {
from {
height: $grading-icon-button-size;
width: $grading-icon-button-size;
border-radius: $grading-icon-button-size / 2;
background-color: $gray-200;
}
to {
width: 100%;
height: $input-height-lg;
border-radius: 0;
background-color: $input-bg;
border-color: $input-border-color;
padding-left: $grading-search-button-padding-left;
padding-top: $input-padding-y-lg;
padding-bottom: $input-padding-y-lg;
@include font-size($input-font-size-lg);
line-height: $input-line-height-lg;
right: 0;
}
}
@keyframes collapseSearchButton {
from {
width: 100%;
height: $input-height-lg;
border-radius: 0;
background-color: $input-bg;
border-color: $input-border-color;
padding-left: $grading-search-button-padding-left;
padding-top: $input-padding-y-lg;
padding-bottom: $input-padding-y-lg;
@include font-size($input-font-size-lg);
line-height: $input-line-height-lg;
right: 0;
}
to {
height: $grading-icon-button-size;
width: $grading-icon-button-size;
border-radius: $grading-icon-button-size / 2;
background-color: $gray-200;
}
}
.path-mod-forum .unified-grader {
.navbar {
max-height: none;
z-index: 1;
}
.body-container {
&.hidden {
display: none !important; /* stylelint-disable-line declaration-no-important */
}
}
.userpicture {
height: 60px;
width: 60px;
}
.grader-grading-panel {
position: absolute;
top: 0;
height: 100%;
z-index: 0;
width: $grading-drawer-width;
&.hidden {
right: ($grading-drawer-width * -1);
}
.grading-icon {
width: $grading-icon-button-size;
}
.user-picker-container {
.user-full-name {
max-width: 240px;
}
.page-link {
width: $grading-icon-button-size;
height: $grading-icon-button-size;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
}
}
.header-container {
height: 65px;
position: relative;
overflow: hidden;
.info-container {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 100%;
height: 100%;
padding: map-get($spacers, 2);
padding-right: calc(#{$grading-icon-button-size} + #{map-get($spacers, 2)});
opacity: 1;
visibility: visible;
transition: left $grading-animation-duration ease-in-out;
z-index: 1;
}
.toggle-search-button {
&.expand {
animation-name: expandSearchButton;
animation-duration: $grading-animation-duration;
animation-timing-function: ease-in-out;
}
&.collapse {
display: block;
animation-name: collapseSearchButton;
animation-duration: $grading-animation-duration;
}
}
.user-search-container {
overflow: hidden;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
z-index: 2;
width: 100%;
height: 100% !important; /* stylelint-disable-line declaration-no-important */
padding: map-get($spacers, 2);
.search-input-container {
position: relative;
overflow: visible;
flex-wrap: nowrap;
input {
padding-left: $grading-search-input-padding-left;
padding-right: $grading-search-input-padding-right;
opacity: 1;
visibility: visible;
transition:
opacity 0s linear $grading-animation-duration,
visibility 0s linear;
}
.search-icon {
position: absolute;
top: 50%;
left: map-get($spacers, 2);
transform: translateY(-50%);
color: $input-color;
height: $grading-icon-button-size;
width: $grading-icon-button-size - ($input-border-width * 2);
background-color: $input-bg;
opacity: 1;
visibility: visible;
transition:
opacity 0s linear $grading-animation-duration,
visibility 0s linear $grading-animation-duration;
}
.toggle-search-button {
position: absolute;
top: 50%;
right: map-get($spacers, 2);
transform: translateY(-50%);
z-index: 1;
color: inherit;
text-align: left;
padding-left: 9px;
transition: right 0s linear $grading-animation-duration;
.expanded-icon {
opacity: 1;
visibility: visible;
max-width: 50px;
max-height: 50px;
transition:
opacity 0s linear $grading-animation-duration,
max-height 0s linear $grading-animation-duration,
max-width 0s linear $grading-animation-duration,
visibility 0s linear $grading-animation-duration;
}
.collapsed-icon {
opacity: 0;
visibility: hidden;
max-height: 0;
max-width: 0;
overflow: hidden;
transition:
opacity 0s linear $grading-animation-duration,
max-height 0s linear $grading-animation-duration,
max-width 0s linear $grading-animation-duration,
visibility 0s linear $grading-animation-duration;
}
}
}
&.collapsed {
width: calc(#{$grading-icon-button-size} + #{map-get($spacers, 2)} + #{map-get($spacers, 2)});
transition: width $grading-animation-duration ease-in-out;
.search-input-container {
flex-wrap: nowrap;
input,
.search-icon {
opacity: 0;
visibility: hidden;
transition:
opacity 0s linear,
visibility 0s linear;
}
input {
padding-left: 0;
padding-right: 0;
}
.toggle-search-button {
.expanded-icon {
opacity: 0;
visibility: hidden;
max-height: 0;
max-width: 0;
overflow: hidden;
transition:
opacity 0s linear,
max-height 0s linear,
max-width 0s linear,
visibility 0s linear;
}
.collapsed-icon {
opacity: 1;
visibility: visible;
max-width: 50px;
max-height: 50px;
transition:
opacity 0s linear,
max-height 0s linear,
max-width 0s linear,
visibility 0s linear;
}
}
}
}
}
.user-search-container:not(.collapsed) + .info-container {
opacity: 0;
visibility: hidden;
left: calc(100% * -1);
transition:
left $grading-animation-duration ease-in-out,
opacity 0s linear $grading-animation-duration,
visibility 0s linear $grading-animation-duration,
padding 0s linear $grading-animation-duration;
}
}
}
.grader-module-content {
overflow-y: auto;
margin-right: $grading-drawer-width;
@include transition(margin-right .2s ease-in-out);
}
.grader-grading-panel.hidden + .grader-module-content {
margin-right: 0;
}
.drawer-button {
position: relative;
&.active::after {
content: "";
position: absolute;
bottom: $grading-nav-bar-active-drawer-button-bottom;
left: 0;
width: 100%;
height: 3px;
background-color: map-get($theme-colors, 'primary');
}
.icon {
font-size: 20px;
height: 20px;
width: 20px;
}
}
.grader-module-content-display {
.discussion-container {
&:last-of-type {
> hr {
display: none;
}
}
.posts-container {
&:last-of-type {
> hr {
display: none;
}
}
.parent-container {
position: relative;
.show-content-button {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
padding-left: $grading-content-show-content-button-padding-left;
text-align: left;
z-index: 1;
&:not(.collapsed) {
display: none;
}
}
.content {
display: block;
height: auto !important; /* stylelint-disable-line declaration-no-important */
.header {
transition: margin-bottom $grading-animation-duration ease-in-out;
div + div {
opacity: 1;
visibility: visible;
max-height: none;
transition:
opacity $grading-animation-duration linear,
visibility 0s linear;
}
}
.body-content-container {
opacity: 1;
visibility: visible;
max-height: none;
transition:
opacity $grading-animation-duration linear,
visibility 0s linear;
}
.forum-post-core {
opacity: 1;
visibility: visible;
max-height: none;
transition:
opacity $grading-animation-duration linear,
visibility 0s linear;
}
}
.show-content-button.collapsed + .content {
opacity: .3;
.header {
margin-bottom: 0 !important; /* stylelint-disable-line declaration-no-important */
div + div {
opacity: 0;
visibility: hidden;
max-height: 0;
}
}
.body-content-container {
opacity: 0;
visibility: hidden;
max-height: 0;
}
.forum-post-core {
opacity: 0;
visibility: hidden;
max-height: 0;
}
}
.show-content-button.collapsed:hover + .content,
.show-content-button.collapsed:focus + .content {
opacity: 1;
}
}
}
}
.no-post-container {
.icon {
height: 250px;
width: 250px;
margin-right: 0;
}
}
.nested-v2-display-mode {
.discussion-container {
.posts-container {
.parent-container {
.show-content-button {
padding-left: $author-image-width + $author-image-margin;
}
}
}
}
}
}
.no-search-results-container {
.icon {
height: 250px;
width: 250px;
margin-right: 0;
}
}
.nested-v2-display-mode {
.view-context-button {
margin-left: $author-image-width + $author-image-margin;
border-radius: $border-radius-lg;
}
.parent-container {
.author-image-container {
position: relative;
&:after {
position: absolute;
top: calc(#{$author-image-width} + #{map-get($spacers, 2)});
content: "";
background-color: $gray-200;
width: 2px;
height: calc(100% - #{$author-image-width} + #{map-get($spacers, 2)});
}
}
}
.parent-container + .post-container {
.author-image-container {
img {
width: $author-image-width-sm !important; /* stylelint-disable-line declaration-no-important */
}
}
}
}
}
.path-mod-forum .unified-grader .nested-v2-display-mode,
.path-mod-forum .modal .nested-v2-display-mode {
.post-subject {
display: none;
}
}
@include media-breakpoint-down(xs) {
.path-mod-forum .unified-grader {
.grader-grading-panel {
width: 100%;
}
}
}
// End styling for mod_forum.
.maincalendar .calendarmonth td,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long