Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

AJAX marking block

From MoodleDocs
Warning: This page is no longer in use. The information contained on the page should NOT be seen as relevant or reliable.

This page outlines the internal architecture of the AJAX marking block and how to extend it for new types of assignment.

Architecture

The block has a server side section of code written in PHP and a client side in javascript. The client is based on the YUI treeview widget and sends asynchronous messages to the server to retrieve the data which becomes the nodes of the tree. Each time a node is clicked to expand it, a new message is sent, with the response data parsed and made into the new sub-nodes.

HTML fallback

To aid accessibility, the block starts by loading a very basic HTML version so that if javascript is turned off either in the browser or the user's preferences, the block is still usable. This HTML version is normally not visible as the javascript acts to hide it immediately if possible.

File structure

The main lib.php file provides a base class which holds most of the useful functions. This is extended through inheritance when either ajax.php is accessed (each time an asynchronous request is sent) or html_list.php is included when the page is initially set up, providing an object which automatically collects submitted POST data and outputs the desired code once instantiated. This file also has a base class, module_base which is extended by each of the modules with a modulename_functions classin the modulename_grading.php file. All of these files are included as needed at the start and the instantiated objects are added to the main library class object as e.g. $AMB_AJAX_response->quiz so that their functions are available. The module objects will need to use many of the library functions, so a reference to the parent library object is passed in via the constructor and is used as $this->mainobject->useful_function().

The javascript.js file contains a collection of functions which are placed within the YAHOO.ajax_marking_block namespace. Some are part of YAHOO.ajax_marking_block.tree_base which is an extended version of the YAHOO.widget.TreeView widget that gets instantiated once for the main tree and once for the configuration tree via a factory function.

Plugins

The block is designed to allow new assessment types to be added dynamically. Rach new type will need to provide two files: modulename_grading.php and modulename_grading.js, whic can be placed either in the /block/ajax_marking folder or in the /mod/modulename folder.

To see how these work, take the assignment_grading files as examples.

PHP

The php file will need the following:

The usual login check

 require_login(0, false);

A class declaration for modulename_function which extends module_base

 class assignment_functions extends module_base {

Constructor

A constructor which lays out the basic information about this module

 function assignment_functions(&$reference) {

The library object (which this object will be attached to) passed in as a reference so that functions can be accessed

 $this->mainobject = $reference;

The type must be identical to the modulename stored in the database

 $this->type = 'assignment';

This is the capability that will need to be checked to see if the person has grading permission i.e. teachers should be able to do this whilst students should not.

 $this->capability = 'mod/assignment:grade';

This is the location of the icon to be displayed for this assessment type. It varies according to which theme setup you have. Smartpix was difficult to integrate, so there is a home-grown solution using this property, at least for 1.9.

 $this->icon = 'mod/assignment/icon.gif';

This array is used to match the types which are returned from the nodes being clicked in the ajax tree to the functions which return the next level of the tree. The initial course->assessment node one is built in, so you just need to add the second and possibly third level connections. In this case, when a node of type 'assignment is clicked, the name of the function that will return the next layer of nodes (the individual student submissions) is 'submissions()'. Groups nodes are dealt with automatically, so there is no need to put them here.

 $this->functions  = array(
      'assignment' => 'submissions'
 );

It is possible that your assessment may have only two levels e.g. the journal module. This would be because there is no screen that allows you to grade individual students' work and you must have a pop up for the entire journal with all students. Alternatively, it may be that you can only grade a student's work for a subdivision of an assessment e.g. one question at a time in the quiz. In this case, you will have four levels: course, quiz, quiz question, student. Specify the number of levels here so that the nodes are constructed properly. 3 is the norm.

 $this->levels = 3;

Javascript

Using the assignment module as an example, the javascript file will need to use the YAHOO.ajax_marking_block.modulename namespace and will have to add the following features:

Make a new namespace for the module:

 YAHOO.ajax_marking_block.assignment = {};

The following functions (in no particular order) all use this namespace and must be included even if empty unless otherwise stated.

Provide arguments for the pop up window that the grading will happen in. The main thing to change here is the height and width so that the grading interface is visible.

 YAHOO.ajax_marking_block.assignment.pop_up_arguments  = function(clicked_node) {
     return 'menubar=0,location=0,scrollbars,resizable,width=780,height=630';
 };

Provide the URL for the pop up window. This will usually involve some combination of the student's userid and the assessement id or coursemodule id. This data is saved in the data attribute of the clicked node and is passed through to this function. You will need to make sure it is passed through by the PHP code on the server.

 YAHOO.ajax_marking_block.assignment.pop_up_opening_url = function (clicked_node) {
     return '/mod/assignment/submissions.php?id='+clicked_node.data.aid+'&userid='+clicked_node.data.sid+'&mode=single&offset=0';
 };

The pop up window needs to be closed after grading has finished, which a small piece of javascript carries out. It does this by checking to see if the URL has changed to the one signifying that your grades have been saved, so grade some work, press 'save' and look to see the URL, which you put in this function.

 YAHOO.ajax_marking_block.assignment.pop_up_closing_url = function (clicked_node) {
     return '/mod/assignment/submissions.php';
 };

There may be a need to send more than just the standard user id and assessment item id with the AJAX request in order to specify what's needed. See the quiz module for an example, where the quiz id and question id are needed as well as the user id. Leave it as below if not required.

 YAHOO.ajax_marking_block.assignment.extra_ajax_request_arguments = function (clicked_node) {
     return true;
 };

You then need to provide code that will alter the pop up's contents so that when the submit button is clicked, the tree nodes are updated. The function below will be run every second from the point at which the pop up is opened until it completes successfully. It aims to test the loaded portion of the DOM to see whether the buttons that need altering are present, then adds an onclick function which will update the tree.

 YAHOO.ajax_marking_block.assignment.alter_popup = function(node_id) {
 
     var els = ;
 
     if (YAHOO.ajax_marking_block.pop_up_holder.document.getElementsByName) {
 
         els = YAHOO.ajax_marking_block.pop_up_holder.document.getElementsByName('submit');
         // the above line will not return anything until the pop up is fully loaded
 
         if (els.length > 0) {
             var functionText   = "return YAHOO.ajax_marking_block.main_instance.remove_node_from_tree(-1, '";
                  functionText += node_id+"', false); ";
 
             els[0]["onclick"] = new Function(functionText);
 
             // cancel the timer loop for this function
             window.clearInterval(YAHOO.ajax_marking_block.timerVar);
         }
     }    
 }