MDL-75455 gradereport_singleview: Add Bulk actions menu.

Part of: MDL-75423
This commit is contained in:
Ilya Tregubov 2022-10-04 16:12:57 +04:00 committed by Mihail Geshoski
parent 21c956273f
commit b837be1e3e
9 changed files with 282 additions and 2 deletions

View File

@ -0,0 +1,10 @@
define("gradereport_singleview/bulkactions",["exports","core/pending","core/custom_interaction_events","core/modal_factory","core/templates","core/modal_events"],(function(_exports,_pending,_custom_interaction_events,_modal_factory,_templates,_modal_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
/**
* Javascript module for bulk actions.
*
* @module gradereport_singleview/bulkactions
* @copyright 2022 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_pending=_interopRequireDefault(_pending),_custom_interaction_events=_interopRequireDefault(_custom_interaction_events),_modal_factory=_interopRequireDefault(_modal_factory),_templates=_interopRequireDefault(_templates),_modal_events=_interopRequireDefault(_modal_events);_exports.init=()=>{const pendingPromise=new _pending.default;registerListenerEvents(),pendingPromise.resolve()};const registerListenerEvents=()=>{const events=["click",_custom_interaction_events.default.events.activate,_custom_interaction_events.default.events.keyboardActivate];_custom_interaction_events.default.define(document,events),events.forEach((event=>{document.addEventListener(event,(async e=>{const trigger=e.target.closest("[data-role]");if(trigger)if("overrideallgrades"===trigger.dataset.role||"overridenonegrades"===trigger.dataset.role){const overrideAll=document.querySelectorAll("input[type=checkbox][name^=override]");if("overridenonegrades"===trigger.dataset.role){const confirm=new M.core.confirm({title:M.util.get_string("removeoverride","gradereport_singleview"),question:M.util.get_string("overridenoneconfirm","gradereport_singleview"),noLabel:M.util.get_string("cancel","moodle"),yesLabel:M.util.get_string("removeoverridesave","gradereport_singleview")});confirm.on("complete-yes",(function(){confirm.hide(),confirm.destroy(),overrideAll.forEach((function(el){el.checked&&el.click()}))}),self),confirm.show()}else overrideAll.forEach((function(el){el.checked||el.click()}))}else if("excludeallgrades"===trigger.dataset.role||"excludenonegrades"===trigger.dataset.role){const excludeAll=document.querySelectorAll("input[type=checkbox][name^=exclude]"),checked="excludeallgrades"===trigger.dataset.role;excludeAll.forEach((function(el){el.checked=checked}))}else"bulklegend"===trigger.dataset.role&&_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,body:_templates.default.render("gradereport_singleview/bulkinsert",{id:"bulkinsertmodal",name:"bulkinsertmodal"}),title:"Bulk insert"}).then((function(modal){return modal.setSaveButtonText("Save"),modal.getFooter().find('[data-action="save"]').attr("disabled",!0),modal.getRoot().on(_modal_events.default.hidden,(function(){modal.getRoot().remove()})),modal.getRoot().on("change",'input[type="checkbox"]',(e=>{if(e.preventDefault(),e.target.checked){modal.getRoot().find(".formdata").removeClass("dimmed_text"),modal.getRoot().find('input[type="radio"]').removeAttr("disabled"),modal.getRoot().find('input[type="text"]').removeAttr("disabled");modal.getRoot().find('input[type="radio"]:checked').val()&&modal.getFooter().find('[data-action="save"]').removeAttr("disabled")}else modal.getRoot().find(".formdata").addClass("dimmed_text"),modal.getRoot().find('input[type="radio"]').attr("disabled",!0),modal.getRoot().find('input[type="text"]').attr("disabled",!0),modal.getFooter().find('[data-action="save"]').attr("disabled",!0)})),modal.getRoot().on("change",'input[type="radio"]',(e=>{e.preventDefault(),modal.getFooter().find('[data-action="save"]').removeAttr("disabled")})),modal.getRoot().on(_modal_events.default.save,(function(){document.querySelector('input[type="checkbox"][name^=bulk]').checked=!0;const formRadioData=modal.getRoot().find('input[type="radio"]:checked').val();document.querySelector("select[name^=bulk]").value=formRadioData;const formData=modal.getRoot().find(".form-control").val();document.querySelector('input[type="text"][name^=bulk]').value=formData,document.querySelector('input[type="submit"]').click()})),modal.show(),modal}))}))}))}}));
//# sourceMappingURL=bulkactions.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,155 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Javascript module for bulk actions.
*
* @module gradereport_singleview/bulkactions
* @copyright 2022 Ilya Tregubov <ilya@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
import Pending from 'core/pending';
import CustomEvents from "core/custom_interaction_events";
import ModalFactory from 'core/modal_factory';
import Templates from 'core/templates';
import ModalEvents from 'core/modal_events';
/**
* Initialize module.
*/
export const init = () => {
const pendingPromise = new Pending();
registerListenerEvents();
pendingPromise.resolve();
};
/**
* Register bulk actions related event listeners.
*
* @method registerListenerEvents
*/
const registerListenerEvents = () => {
const events = [
'click',
CustomEvents.events.activate,
CustomEvents.events.keyboardActivate
];
CustomEvents.define(document, events);
// Register events.
events.forEach((event) => {
document.addEventListener(event, async(e) => {
const trigger = e.target.closest('[data-role]');
if (trigger) {
if ((trigger.dataset.role === 'overrideallgrades') || (trigger.dataset.role === 'overridenonegrades')) {
const overrideAll = document.querySelectorAll('input[type=checkbox][name^=override]');
if (trigger.dataset.role === 'overridenonegrades') {
const confirm = new M.core.confirm({
title: M.util.get_string('removeoverride', 'gradereport_singleview'),
question: M.util.get_string('overridenoneconfirm', 'gradereport_singleview'),
noLabel: M.util.get_string('cancel', 'moodle'),
yesLabel: M.util.get_string('removeoverridesave', 'gradereport_singleview')
});
confirm.on('complete-yes', function () {
confirm.hide();
confirm.destroy();
overrideAll.forEach(function (el) {
if (el.checked) {
el.click();
}
});
}, self);
confirm.show();
} else {
overrideAll.forEach(function (el) {
if (!el.checked) {
el.click();
}
});
}
} else if ((trigger.dataset.role === 'excludeallgrades') || (trigger.dataset.role === 'excludenonegrades')) {
const excludeAll = document.querySelectorAll('input[type=checkbox][name^=exclude]');
const checked = (trigger.dataset.role === 'excludeallgrades');
excludeAll.forEach(function (el) {
el.checked = checked;
});
} else if (trigger.dataset.role === 'bulklegend') {
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
body: Templates.render('gradereport_singleview/bulkinsert', {
id: 'bulkinsertmodal',
name: 'bulkinsertmodal'
}),
title: 'Bulk insert',
})
.then(function (modal) {
modal.setSaveButtonText('Save');
modal.getFooter().find('[data-action="save"]').attr('disabled', true);
modal.getRoot().on(ModalEvents.hidden, function () {
modal.getRoot().remove();
});
modal.getRoot().on('change', 'input[type="checkbox"]',
(e) => {
e.preventDefault();
if (e.target.checked) {
modal.getRoot().find('.formdata').removeClass('dimmed_text');
modal.getRoot().find('input[type="radio"]').removeAttr('disabled');
modal.getRoot().find('input[type="text"]').removeAttr('disabled');
const formRadioData = modal.getRoot().find('input[type="radio"]:checked').val();
if (formRadioData) {
modal.getFooter().find('[data-action="save"]').removeAttr('disabled');
}
} else {
modal.getRoot().find('.formdata').addClass('dimmed_text');
modal.getRoot().find('input[type="radio"]').attr('disabled', true);
modal.getRoot().find('input[type="text"]').attr('disabled', true);
modal.getFooter().find('[data-action="save"]').attr('disabled', true);
}
});
modal.getRoot().on('change', 'input[type="radio"]',
(e) => {
e.preventDefault();
modal.getFooter().find('[data-action="save"]').removeAttr('disabled');
});
modal.getRoot().on(ModalEvents.save, function () {
document.querySelector('input[type="checkbox"][name^=bulk]').checked = true;
const formRadioData = modal.getRoot().find('input[type="radio"]:checked').val();
const $select = document.querySelector('select[name^=bulk]');
$select.value = formRadioData;
const formData = modal.getRoot().find('.form-control').val();
document.querySelector('input[type="text"][name^=bulk]').value = formData;
document.querySelector('input[type="submit"]').click();
});
modal.show();
return modal;
});
}
}
});
});
};

View File

@ -246,7 +246,8 @@ abstract class screen {
'requires' => ['base', 'dom', 'event', 'event-simulate', 'io-base']
];
$PAGE->requires->string_for_js('overridenoneconfirm', 'gradereport_singleview');
$PAGE->requires->strings_for_js(['overridenoneconfirm', 'removeoverride', 'removeoverridesave'],
'gradereport_singleview');
$PAGE->requires->js_init_call('M.gradereport_singleview.init', [], false, $module);
}

View File

@ -66,6 +66,8 @@ class action_bar extends \core_grades\output\action_bar {
* @return array
*/
public function export_for_template(renderer_base $output) {
global $USER;
$courseid = $this->context->instanceid;
// Get the data used to output the general navigation selector.
$generalnavselector = new \core_grades\output\general_action_bar(
@ -92,6 +94,10 @@ class action_bar extends \core_grades\output\action_bar {
$data['pbarurl'] = $this->report->pbarurl->out(false);
if (!empty($USER->editing) && isset($this->report->screen->item)) {
$data['bulkactions'] = $this->report->bulk_actions_menu($output);
}
return $data;
}
}

View File

@ -19,6 +19,7 @@ namespace gradereport_singleview\report;
use context_course;
use grade_report;
use moodle_url;
use renderer_base;
use stdClass;
defined('MOODLE_INTERNAL') || die;
@ -167,4 +168,33 @@ class singleview extends grade_report {
$this->itemselector = $renderer->grade_items_selector($this->course, $itemid);
}
}
/**
* Adds bulk actions menu.
*
* @param renderer_base $output
* @return string HTML to display
*/
public function bulk_actions_menu(renderer_base $output) : string {
$options = [
'overrideallgrades' => get_string('overrideallgrades', 'gradereport_singleview'),
'overridenonegrades' => get_string('overridenonegrades', 'gradereport_singleview'),
'excludeallgrades' => get_string('excludeallgrades', 'gradereport_singleview'),
'excludenonegrades' => get_string('excludenonegrades', 'gradereport_singleview'),
'bulklegend' => get_string('bulklegend', 'gradereport_singleview')
];
$menu = new \action_menu();
$menu->set_menu_trigger(get_string('actions'), 'text-dark');
foreach ($options as $type => $option) {
$action = new \action_menu_link_secondary(new \moodle_url('#'), null, $option,
['data-role' => $type]);
$menu->add($action);
}
$menu->attributes['class'] .= ' float-left my-auto';
return $output->render($menu);
}
}

View File

@ -30,14 +30,18 @@ $string['assessmentname'] = 'Grade item';
$string['blanks'] = 'Empty grades';
$string['bulkappliesto'] = 'For';
$string['bulkinsertvalue'] = 'Insert value';
$string['bulkinsertvaluemodal'] = 'Insert value modal';
$string['bulklegend'] = 'Bulk insert';
$string['bulkchoice'] = 'For which grades do you want to insert?';
$string['bulkperform'] = 'Perform bulk insert';
$string['bulkfor'] = 'Grades for {$a}';
$string['entrypage'] = 'Grade user or grade item';
$string['exclude'] = 'Exclude';
$string['excludeall'] = 'Exclude all grades';
$string['excludeallgrades'] = 'Exclude All';
$string['excludefor'] = 'Exclude for {$a}';
$string['excludenone'] = 'Do not exclude any grades';
$string['excludenonegrades'] = 'Exclude None';
$string['eventgradereportviewed'] = 'Grade single view report viewed.';
$string['feedbackfor'] = 'Feedback for {$a}';
$string['gradefor'] = 'Grade for {$a}';
@ -51,11 +55,15 @@ $string['itemsperpage'] = 'Items per page';
$string['notvalid'] = 'Not a valid Single view screen: {$a}';
$string['override'] = 'Override';
$string['overrideall'] = 'Override all grades';
$string['overrideallgrades'] = 'Override All';
$string['overridefor'] = 'Override for {$a}';
$string['overridenone'] = 'Do not override any grades';
$string['overridenoneconfirm'] = 'You are about to disable grade overrides. This will remove all previously overridden grades. Are you sure you want to continue?';
$string['overridenonegrades'] = 'Override None';
$string['overridenoneconfirm'] = 'This will remove all previously entered overridden grades on this page when you save changes.';
$string['pluginname'] = 'Single view';
$string['privacy:metadata'] = 'The Grade single view report only shows data stored in other locations.';
$string['removeoverride'] = 'Remove grade overrides';
$string['removeoverridesave'] = 'Remove overrides';
$string['savegrades'] = 'Saving grades';
$string['save'] = 'Save';
$string['savegradessuccess'] = 'Grades were set for {$a} items';
@ -64,6 +72,9 @@ $string['selectuser'] = 'Select user...';
$string['singleview:view'] = 'View report';
$string['summarygrade'] = 'A table of users, with columns for range, grade, feedback, and whether to override or exclude a particular grade.';
$string['summaryuser'] = 'A table of grade items, with columns for grade category, range, grade, feedback, and whether to override or exclude a particular grade.';
$string['unsavedataalert'] = 'If you have unsave changes in grades table, you might lose some data when chosing "All grades" and click Save.';
$string['unsavedataconfirm'] = 'I understand that my unsaved data might be lost';
$string['users'] = 'Users';
$string['userselect'] = 'Select activity';
$string['ariareporttype'] = 'Select a report type to view';

View File

@ -39,6 +39,15 @@
{{/itemselector}}
{{#pagetoggler}}
<div class="d-flex ml-auto">
{{#bulkactions}}
<div class="navitem-divider"></div>
<div class="navitem">{{{bulkactions}}}</div>
{{#js}}
require(['gradereport_singleview/bulkactions'], function(bulkactions) {
bulkactions.init();
});
{{/js}}
{{/bulkactions}}
<div class="navitem-divider"></div>
<div class="navitem">
{{>gradereport_singleview/page_toggler}}

View File

@ -0,0 +1,57 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template core_message/send_bulk_message
Template for the bulk insert grades modal.
Context variables required for this template:
None
Example context (json):
{
}
}}
<form>
<div class="alert alert-danger">
{{#str}}unsavedataalert, gradereport_singleview{{/str}}
<div class="form-check form-check-inline">
<input class="form-check-input" type="checkbox" value="1" id="override">
<label class="form-check-label" for="override">
{{#str}}unsavedataconfirm, gradereport_singleview{{/str}}
</label>
</div>
</div>
<div class="formdata dimmed_text">
<p>
{{#str}}bulkchoice, gradereport_singleview{{/str}}
<div class="pt-3 px-3" role="radiogroup">
<label class="form-check">
<input class="form-check-input" type="radio" name="bulkinsert" value="all" disabled/>
{{#str}}all_grades, gradereport_singleview{{/str}}
</label>
<label class="form-check">
<input class="form-check-input" type="radio" name="bulkinsert" value="blanks" disabled/>
{{#str}}blanks, gradereport_singleview{{/str}}
</label>
</div>
</p>
<p class ="font-weight-bold">
{{#str}}bulkinsertvalue, gradereport_singleview{{/str}}
</p>
<label for="{{name}}">{{#str}}bulkinsertvaluemodal, gradereport_singleview{{/str}}</label>
<input type="text" name="{{name}}" id="{{id}}" value="0" class="form-control text-ltr" disabled {{#readonly}}readonly{{/readonly}}>
</div>
</form>