MDL-66893 mod_forum: update grading panel UI in grader

This commit is contained in:
Ryan Wyllie 2019-11-05 13:15:12 +08:00
parent 4e53672929
commit 46d51c8ca9
15 changed files with 769 additions and 337 deletions

View File

@ -357,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.';

View File

@ -241,6 +241,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"

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")},regions:{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")}};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","regions","moduleReplace","pickerRegion","gradingPanel","gradingPanelContainer","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,qBAAqB,CAAEX,CAAe,CAAC,QAAD,CAAW,yBAAX,CAJjC,CAKLY,kBAAkB,CAAEZ,CAAe,CAAC,QAAD,CAAW,cAAX,CAL9B,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 gradingPanelContainer: getDataSelector('region', 'grading-panel-container'),\n gradingPanelErrors: getDataSelector('region', 'grade-errors'),\n },\n};\n\n"],"file":"selectors.min.js"}

View File

@ -87,7 +87,10 @@ 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);
const panelContainer = root.querySelector(Selectors.regions.gradingPanelContainer);
const panel = panelContainer.querySelector(Selectors.regions.gradingPanel);
Templates.replaceNodeContents(panel, gradingPanelHtml, gradingPanelJS);
panelContainer.scrollTop = 0;
spinner.resolve();
};
};
@ -189,18 +192,21 @@ export const launch = async(getListOfUsers, getContentForUser, getGradeForUser,
// 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,
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);
// Fetch the userpicker for display.

View File

@ -42,6 +42,7 @@ export default {
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'),
},
};

View File

@ -34,16 +34,16 @@
"cmid": 1337
}
}}
<div class="container-fluid"
<div
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>

View File

@ -32,24 +32,63 @@
{
}
}}
<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 collapse">
<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-action="search-user-input"
class="form-control form-control-lg"
placeholder="Search user"
>
<button
class="toggle-search-button btn btn-icon icon-no-margin"
data-target="#searchbox-{{uniqid}}"
aria-expanded="false"
aria-controls="searchbox-{{uniqid}}"
data-toggle="collapse"
>
<div class="expanded-icon">{{#pix}} e/cancel, core {{/pix}}</div>
<div class="collapsed-icon">{{#pix}} i/search, core {{/pix}}</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>
</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>
<div data-region="grade-errors" role="alert" aria-role="assertive"></div>
<hr/>
</div>
</div>
{{/drawercontent}}
{{/core/drawer}}

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,6 @@ $author-image-margin-sm: 8px;
}
}
#page-mod-forum-view [data-region="unified-grader"],
.path-mod-forum.nested-v2-display-mode {
.discussionsubscription {
margin-top: 0;
@ -426,6 +425,275 @@ $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;
@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 {
.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 {
.userpicture {
height: 60px;
width: 60px;
}
.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;
}
.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;
transition: $custom-forms-transition;
}
.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;
}
input,
.search-icon {
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;
animation-name: expandSearchButton;
animation-duration: $grading-animation-duration;
animation-timing-function: ease-in-out;
transition: right 0s linear $grading-animation-duration;
.expanded-icon {
opacity: 1;
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;
}
.collapsed-icon {
opacity: 0;
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;
}
}
}
&.collapse:not(.show) {
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 {
animation-name: collapseSearchButton;
animation-duration: $grading-animation-duration;
.expanded-icon {
opacity: 0;
max-height: 0;
max-width: 0;
overflow: hidden;
transition:
opacity 0s linear,
max-height 0s linear,
max-width 0s linear;
}
.collapsed-icon {
opacity: 1;
max-width: 50px;
max-height: 50px;
transition:
opacity 0s linear,
max-height 0s linear,
max-width 0s linear;
}
}
}
}
}
.user-search-container.show + .info-container,
.user-search-container.collapsing + .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;
}
}
@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