Skip to content

Commit

Permalink
MDL-48771 quiz: Select multiple questions to delete
Browse files Browse the repository at this point in the history
Upon Moodle 2.8 the option to bulk delete all questions of a quiz
disappeared.
This patch adresses this and reintruduces a bulk action button.
Pushing that button shows a Delete and a Cancel button as well as
two Select all / Deselect all triggers and each and every question
gets a checkbox. The UI is slimmed down and other elements (e.g.
'Repaginate' button and so on) are hidden. Questions can be chosen
and deleted by pushing the Delete button. The bulk action button
is disabled when quiz attempts are present, just like the
'Repaginate' button.

TODO: Behat tests are lacking.
  • Loading branch information
lucaboesch authored and timhunt committed Apr 3, 2017
1 parent bf919dd commit 5d803e5
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 9 deletions.
39 changes: 37 additions & 2 deletions mod/quiz/classes/output/edit_renderer.php
Expand Up @@ -62,11 +62,23 @@ public function edit_page(\quiz $quizobj, structure $structure,
$output .= $this->quiz_information($structure);
$output .= $this->maximum_grade_input($structure, $pageurl);
$output .= $this->repaginate_button($structure, $pageurl);
$output .= $this->bulkaction_button($structure);
$output .= $this->total_marks($quizobj->get_quiz());

// Show the questions organised into sections and pages.
$output .= $this->start_section_list($structure);

// Bulk action button delete and bulk action button cancel.
$output .= html_writer::tag('div', html_writer::empty_tag('input', array('type' => 'button',
'id' => 'bulkactionsdeletecommand', 'value' => get_string('delete', 'moodle'))) . " " .
html_writer::empty_tag('input', array('type' => 'button', 'id' => 'bulkactionscancelcommand',
'value' => get_string('cancel', 'moodle'))), array('class' => 'bulkactioncommand actions'));

// Select all/deselect all questions.
$output .= html_writer::tag('div', html_writer::link('#', get_string('selectall', 'quiz'),
array('id' => 'questionselectall')) . " / " . html_writer::link('#', get_string('selectnone', 'quiz'),
array('id' => 'questiondeselectall')), array('class' => 'bulkactioncommandbuttons'));

foreach ($structure->get_sections() as $section) {
$output .= $this->start_section($structure, $section);
$output .= $this->questions_in_section($structure, $section, $contexts, $pagevars, $pageurl);
Expand Down Expand Up @@ -207,8 +219,26 @@ protected function repaginate_button(structure $structure, \moodle_url $pageurl)
$this->page->requires->yui_module('moodle-mod_quiz-repaginate', 'M.mod_quiz.repaginate.init');
}

return html_writer::tag('div',
html_writer::empty_tag('input', $buttonoptions), $containeroptions);
return html_writer::start_tag('div', $containeroptions) .
html_writer::empty_tag('input', $buttonoptions);
}

/**
* Generate the bulk action button
* @param structure $structure the structure of the quiz being edited.
* @return string HTML to output.
*/
protected function bulkaction_button(structure $structure) {
$buttonoptions = array(
'type' => 'button',
'name' => 'repaginate',
'id' => 'bulkactionscommand',
'value' => get_string('bulkactions', 'quiz'),
);
if (!$structure->can_be_repaginated()) {
$buttonoptions['disabled'] = 'disabled';
}
return html_writer::empty_tag('input', $buttonoptions) . html_writer::end_tag('div');
}

/**
Expand Down Expand Up @@ -640,6 +670,10 @@ public function question(structure $structure, $slot, \moodle_url $pageurl) {
}

$output .= html_writer::start_div('mod-indent-outer');
$output .= html_writer::tag('input', '', array('id' => 'selectquestion-' .
$structure->get_displayed_number_for_slot($slot), 'name' => 'selectquestion[]',
'type' => 'checkbox', 'class' => 'quiz-question-bulk-selector',
'value' => $structure->get_displayed_number_for_slot($slot)));
$output .= $this->question_number($structure->get_displayed_number_for_slot($slot));

// This div is used to indent the content.
Expand Down Expand Up @@ -1024,6 +1058,7 @@ protected function initialise_editing_javascript(structure $structure,
unset($config->pagehtml);
unset($config->addpageiconhtml);

$this->page->requires->strings_for_js(array('areyousureremoveselected'), 'quiz');
$this->page->requires->yui_module('moodle-mod_quiz-toolboxes',
'M.mod_quiz.init_section_toolbox',
array(array(
Expand Down
18 changes: 18 additions & 0 deletions mod/quiz/edit_rest.php
Expand Up @@ -47,6 +47,7 @@
$newheading = optional_param('newheading', '', PARAM_TEXT);
$shuffle = optional_param('newshuffle', 0, PARAM_INT);
$page = optional_param('page', '', PARAM_INT);
$bulkslots = optional_param('slots', '', PARAM_SEQUENCE);
$PAGE->set_url('/mod/quiz/edit-rest.php',
array('quizid' => $quizid, 'class' => $class));

Expand Down Expand Up @@ -144,6 +145,23 @@
echo json_encode(array('slots' => $json));
break;

case 'bulkdelete':
require_capability('mod/quiz:manage', $modcontext);

$bulkslots = explode(',', $bulkslots);
rsort($bulkslots); // Work backwards, since removing a question renumbers following slots.

foreach ($bulkslots as $slot) {
if (quiz_has_question_use($quiz, $slot)) {
$structure->remove_slot($slot);
}
}
quiz_delete_previews($quiz);
quiz_update_sumgrades($quiz);

echo json_encode(array('deleted' => true));
break;

case 'updatedependency':
require_capability('mod/quiz:manage', $modcontext);
$slot = $structure->get_slot_by_id($id);
Expand Down
1 change: 1 addition & 0 deletions mod/quiz/lang/en/quiz.php
Expand Up @@ -121,6 +121,7 @@
* The quiz will only start if the student has a JavaScript-enabled web-browser
* The quiz appears in a full screen popup window that covers all the other windows and has no navigation controls
* Students are prevented, as far as is possible, from using facilities like copy and paste';
$string['bulkactions'] = 'Bulk actions';
$string['calculated'] = 'Calculated';
$string['calculatedquestion'] = 'Calculated question not supported at line {$a}. The question will be ignored';
$string['cannotcreatepath'] = 'Path cannot be created ({$a})';
Expand Down
66 changes: 62 additions & 4 deletions mod/quiz/styles.css
Expand Up @@ -879,10 +879,6 @@ table.quizreviewsummary td.cell {
width: 100%;
}

#page-mod-quiz-edit ul.slots li.section li.activity .mod-indent-outer {
padding-left: 22px;
}

#page-mod-quiz-edit ul.slots .activityinstance form {
display: inline;
}
Expand Down Expand Up @@ -1117,6 +1113,68 @@ table#categoryquestions {
background-color: #fff;
}

/* Bulk edit actions */

.bulkactioncommandbuttons {
margin: 0.6em 0.4em;
}

.bulkactioncommand,
.bulkactioncommandbuttons,
.quiz-question-bulk-selector {
display: none;
}

body.quiz-bulk-action-mode .bulkactioncommand,
body.quiz-bulk-action-mode .bulkactioncommandbuttons,
body.quiz-bulk-action-mode .quiz-question-bulk-selector {
display: inherit;
}

body.quiz-bulk-action-mode input.quiz-question-bulk-selector[type="checkbox"] {
display: inline;
}

body.quiz-bulk-action-mode .mod-quiz-edit-content .section .activity .editing_move,
body.quiz-bulk-action-mode .mod-quiz-edit-content .section .activity .commands {
display: none;
}

body.quiz-bulk-action-mode .mod-quiz-edit-content .section .page_split_join_wrapper {
display: none;
}

body.quiz-bulk-action-mode .mod-quiz-edit-content .section .activity .actions {
display: none;
}

body.quiz-bulk-action-mode#page-mod-quiz-edit .maxgrade,
body.quiz-bulk-action-mode#page-mod-quiz-edit .totalpoints,
body.quiz-bulk-action-mode .mod-quiz-edit-content .last-add-menu {
display: none;
}

body.quiz-bulk-action-mode .mod-quiz-edit-content .section-heading,
body.quiz-bulk-action-mode .mod-quiz-edit-content .section-heading form,
body.quiz-bulk-action-mode .mod-quiz-edit-content .section-heading .instancesectioncontainer,
body.quiz-bulk-action-mode .mod-quiz-edit-content .section-heading .instanceshufflequestions,
body.quiz-bulk-action-mode .mod-quiz-edit-content .section-heading .instancesectioncontainer h3 {
display: none;
}

body.quiz-bulk-action-mode .mod-quiz-edit-content .rpcontainerclass {
display: none;
}

body.quiz-bulk-action-mode#page-mod-quiz-edit ul.slots li.section li.activity .mod-indent-outer {
padding-left: 3px;
}

.section .summary .iconsmall,
.section .activity .iconsmall {
float: left;
}

/* Base theme needs extra support. */
#page-mod-quiz-edit ul.slots li.section ul.section {
list-style: none;
Expand Down
Expand Up @@ -676,6 +676,77 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
M.mod_quiz.resource_toolbox = null;
M.mod_quiz.init_resource_toolbox = function(config) {
M.mod_quiz.resource_toolbox = new RESOURCETOOLBOX(config);

var bulkactions = function() {
var CSS = {
QUIZBULKACTIONMODE: 'quiz-bulk-action-mode'
},
SELECTOR = {
BULKACTIONS: '#bulkactionscommand',
CANCELBULKACTIONS: '#bulkactionscancelcommand',
SELECTALL: '#questionselectall',
DELETEACTION: '#bulkactionsdeletecommand',
DESELECTALL: '#questiondeselectall',
CHECKBOXES: '.quiz-question-bulk-selector'

};
Y.one(SELECTOR.BULKACTIONS).on('click', function(e) {
e.preventDefault();
Y.one('body').addClass(CSS.QUIZBULKACTIONMODE);
});

Y.one(SELECTOR.CANCELBULKACTIONS).on('click', function(e) {
e.preventDefault();
Y.one('body').removeClass(CSS.QUIZBULKACTIONMODE);
});

Y.one(SELECTOR.SELECTALL).on('click', function(e) {
e.preventDefault();
Y.all(SELECTOR.CHECKBOXES).set('checked', 'checked');
});

Y.one(SELECTOR.DESELECTALL).on('click', function(e) {
e.preventDefault();
Y.all(SELECTOR.CHECKBOXES).set('checked', '');
});

var submitdeletion = function() {
var slots = '';
Y.all(SELECTOR.CHECKBOXES + ':checked').each(function(node) {
slots += slots === '' ? '' : ',';
slots += node.get('value');
});
var spinnercont = Y.one('div.mod-quiz-edit-content'),
spinner = M.mod_quiz.resource_toolbox.add_spinner(spinnercont),
data = {
'class': 'resource',
field: 'bulkdelete',
slots: slots
};
M.mod_quiz.resource_toolbox.send_request(data, spinner, function() {
Y.all(SELECTOR.CHECKBOXES + ':checked').each(function(node) {
node.ancestor('li.activity').remove(true);
});
});
};

Y.one(SELECTOR.DELETEACTION).on('click', function(e) {
e.preventDefault();
// Create the confirmation dialogue.
var confirm = new M.core.confirm({
question: M.util.get_string('areyousureremoveselected', 'quiz'),
modal: true
});

// If it is confirmed.
confirm.on('complete-yes', function() {
submitdeletion();
}, self);
});
};

bulkactions();

return M.mod_quiz.resource_toolbox;
};
/* global TOOLBOX, BODY, SELECTOR */
Expand Down

0 comments on commit 5d803e5

Please sign in to comment.