Pages

Friday, May 1, 2015

How would you like to view a Moodle Quiz's Summary Of Attempt table in multiple column format instead of one long list

Source: http://en.wikipedia.org/wiki/Dead_Sea_Scrolls

This post is seventeen (17!) months in the making. Back then I was using Moodle 2.5. It took so long to do because back in November 2013, I was faced with the challenge of redesigning the Summary of Attempt table, but was easily defeated by the complexity of the quiz's renderer.php code.  Ah! Such is the agony of defeat. I found it too difficult to solve, so I left it by the wayside - only to re-attempt the problem in April 2015. You might say that the idea was gestating all this time. By the time I had the solution, which was on 29th April 2015, Moodle had evolved into Moodle 2.8.5. The feeling of the thrill of success is indescribable. Something to be savoured.

At the end of this post, you will be able to have your Moodle quiz display the "Summary of Attempt" in a whole new way, without the usual "scroll of death".

By default, the Summary Of Attempt table in a Moodle Quiz will display as a single column. So a quiz of 50 quiz questions will result in table that extends for most of the screen's height. Here's what my summary looks like with a quiz of 20 questions.

In the example above, I have to scroll all the way down to access and to click the "Submit all and Finish' or 'Return to attempt' buttons. Here's what the table looks like with 49 quiz questions!



Yikes! A long list is generated and I had to scroll all the way down the screen in order to click the "Submit all and finish" button. Now what happens when you have a quiz that consists of 60, 70, 80 or even 100 questions? Think about it.

Hmm.....now then...

Source: http://upload.wikimedia.org/wikipedia/en/d/d9/Thinking.jpg



...WHAT IF the table could be redesigned like the one below?


Firstly, the table is now divided into 3 separate columns. The questions snake up-down-and-left-to-right in fashion.  The question numbers are automatically and dynamically generated in their respective columns . In addition, the status of all unanswered questions are shown as red text so that the user has a instant visual cue.



The solution was a journey that consisted of many parts. My first problem was to simulate the layout of the question numbers. I started by sketching the solution on paper. Then I wrote a C++ program. Well, more than a couple since I had to prototype them. Thank God of for loops! Here is the first useful program I wrote and tested on Ideone.com. I divided a sequence of numbers into two columns.


However, I needed to generate the numbers as three columns, So my next attempt was this.


So the three columns were producing the numbers in the correct sequence. The programs above took a while to write. The website Ideone.com was invaluable at this stage of the development.

The solution involved modifying this function in /mod/quiz/renderer.php. No easy task.

/**
* Generates the table of summarydata
*
* @param quiz_attempt $attemptobj
* @param mod_quiz_display_options $displayoptions
*/
public function summary_table($attemptobj, $displayoptions) {
   // Prepare the summary table header.
   $table = new html_table();
   $table->attributes['class'] = 'generaltable quizsummaryofattempt boxaligncenter';
   $table->head = array(get_string('question', 'quiz'), get_string('status', 'quiz'));
   $table->align = array('left', 'left');
   $table->size = array('', '');
   $markscolumn = $displayoptions->marks >= question_display_options::MARK_AND_MAX;
   if ($markscolumn) {
      $table->head[] = get_string('marks', 'quiz');
      $table->align[] = 'left';
      $table->size[] = '';
   }
   $table->data = array();
   // Get the summary info for each question.
   $slots = $attemptobj->get_slots();
   foreach ($slots as $slot) {
      if (!$attemptobj->is_real_question($slot)) {
         continue;
      }
      $flag = '';
      if ($attemptobj->is_question_flagged($slot)) {
         $flag = html_writer::empty_tag('img', array('src' => $this->pix_url('i/flagged'),
         'alt' => get_string('flagged', 'question'), 'class' => 'questionflag icon-post'));
      }
      if ($attemptobj->can_navigate_to($slot)) {
         $row = array(html_writer::link($attemptobj->attempt_url($slot),
         $attemptobj->get_question_number($slot) . $flag),
         $attemptobj->get_question_status($slot, $displayoptions->correctness));
      } else {
               $row = array($attemptobj->get_question_number($slot) . $flag,
               $attemptobj->get_question_status($slot, $displayoptions->correctness));
             }
      if ($markscolumn) {
         $row[] = $attemptobj->get_question_mark($slot);
      }
      $table->data[] = $row;
      $table->rowclasses[] = $attemptobj->get_question_state_class(
      $slot, $displayoptions->correctness);
   }
   // Print the summary table.
   $output = html_writer::table($table);
   return $output;
}

On 29th April 2015, I finally solved it. Here is the product of my labour, working with Moodle 2.7.2. I hope you enjoy it.


Download the files:
 /mod/quiz/renderer.php
public_function_summary_table.php

Click here and/or here to see the comparison between the original renderer.php and the modified renderer.php.

If you find this code useful for your work, please do post a comment below. If you like this work, could I also be so bold as to ask if you could click the G+1 (Google Plus Like) button below as well? Just asking. ;-)

Regards
Frankie Kam, Malaysia

Moodle.org Forum references:
https://moodle.org/mod/forum/discuss.php?d=244735
https://moodle.org/mod/forum/discuss.php?d=312598

If you like this post or site
a small donation would be nice but would last only a day,
otherwise leaving a comment (or a compliment) below will last me a month!

Ratings and Recommendations by outbrain