MDL-32932: Add quickgrading support to mod_assign
authorDamyon Wiese <damyon.wiese@netspot.com.au>
Tue, 15 May 2012 05:33:59 +0000 (13:33 +0800)
committerDamyon Wiese <damyon.wiese@netspot.com.au>
Tue, 15 May 2012 05:33:59 +0000 (13:33 +0800)
mod/assign/gradingbatchoperationsform.php
mod/assign/gradingoptionsform.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/module.js
mod/assign/quickgradingform.php [new file with mode: 0644]
mod/assign/renderable.php
mod/assign/renderer.php
mod/assign/styles.css

index 82d08b2..626a7cc 100644 (file)
@@ -53,7 +53,7 @@ class mod_assign_grading_batch_operations_form extends moodleform {
         if ($instance['submissiondrafts']) {
             $options['reverttodraft'] = get_string('reverttodraft', 'assign');
         }
-        $mform->addElement('select', 'operation', get_string('batchoperationsdescription', 'assign'), $options, array('class'=>'operation'));
+        $mform->addElement('select', 'operation', get_string('batchoperationsdescription', 'assign'), $options, array('class'=>'operation ignoredirty'));
         $mform->addHelpButton('operation', 'batchoperationsdescription', 'assign');
         $mform->addElement('hidden', 'action', 'batchgradingoperation');
         $mform->addElement('hidden', 'id', $instance['cm']);
index 5d38834..d9abe0f 100644 (file)
@@ -48,10 +48,16 @@ class mod_assign_grading_options_form extends moodleform {
         $mform->addElement('header', 'general', get_string('gradingoptions', 'assign'));
         // visible elements
         $options = array(-1=>'All',10=>'10', 20=>'20', 50=>'50', 100=>'100');
-        $autosubmit = array('onchange'=>'form.submit();');
-        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options, $autosubmit);
+        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options, array('class'=>'ignoredirty'));
         $options = array(''=>get_string('filternone', 'assign'), ASSIGN_FILTER_SUBMITTED=>get_string('filtersubmitted', 'assign'), ASSIGN_FILTER_REQUIRE_GRADING=>get_string('filterrequiregrading', 'assign'));
-        $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options, $autosubmit);
+        $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options, array('class'=>'ignoredirty'));
+
+        // quickgrading
+        if ($instance['showquickgrading']) {
+            $mform->addElement('checkbox', 'quickgrading', get_string('quickgrading', 'assign'), '', array('class'=>'ignoredirty'));
+            $mform->addHelpButton('quickgrading', 'quickgrading', 'assign');
+            $mform->setDefault('quickgrading', $instance['quickgrading']);
+        }
 
         // hidden params
         $mform->addElement('hidden', 'contextid', $instance['contextid']);
index 3ab2e07..a48eb0b 100644 (file)
@@ -48,6 +48,8 @@ class assign_grading_table extends table_sql implements renderable {
     private $gradinginfo = null;
     /** @var int $tablemaxrows */
     private $tablemaxrows = 10000;
+    /** @var boolean $quickgrading */
+    private $quickgrading = false;
 
     /**
      * overridden constructor keeps a reference to the assignment class that is displaying this table
@@ -56,12 +58,14 @@ class assign_grading_table extends table_sql implements renderable {
      * @param int $perpage how many per page
      * @param string $filter The current filter
      * @param int $rowoffset For showing a subsequent page of results
+     * @param bool $quickgrading Is this table wrapped in a quickgrading form?
      */
-    function __construct(assign $assignment, $perpage, $filter, $rowoffset=0) {
+    function __construct(assign $assignment, $perpage, $filter, $rowoffset, $quickgrading) {
         global $CFG, $PAGE, $DB;
         parent::__construct('mod_assign_grading');
         $this->assignment = $assignment;
         $this->perpage = $perpage;
+        $this->quickgrading = $quickgrading;
         $this->output = $PAGE->get_renderer('mod_assign');
 
         $this->define_baseurl(new moodle_url($CFG->wwwroot . '/mod/assign/view.php', array('action'=>'grading', 'id'=>$assignment->get_course_module()->id)));
@@ -115,7 +119,7 @@ class assign_grading_table extends table_sql implements renderable {
 
         // Select
         $columns[] = 'select';
-        $headers[] = get_string('select') . '<div class="selectall"><input type="checkbox" name="selectall" title="' . get_string('selectall') . '"/></div>';
+        $headers[] = get_string('select') . '<div class="selectall"><input type="checkbox" class="ignoredirty" name="selectall" title="' . get_string('selectall') . '"/></div>';
 
         // Edit links
         if (!$this->is_downloading()) {
@@ -224,13 +228,14 @@ class assign_grading_table extends table_sql implements renderable {
      * Display a grade with scales etc.
      *
      * @param string $grade
+     * @param boolean $editable
      * @return string The formatted grade
      */
-    function display_grade($grade) {
+    function display_grade($grade, $editable, $userid, $modified) {
         if ($this->is_downloading()) {
             return $grade;
         }
-        $o = $this->assignment->display_grade($grade);
+        $o = $this->assignment->display_grade($grade, $editable, $userid, $modified);
 
         return $o;
     }
@@ -247,7 +252,20 @@ class assign_grading_table extends table_sql implements renderable {
             $options = make_grades_menu(-$outcome->scaleid);
 
             $options[0] = get_string('nooutcome', 'grades');
-            $outcomes .= $this->output->container($outcome->name . ': ' . $options[$outcome->grades[$row->userid]->grade], 'outcome');
+            if ($this->quickgrading&& !($outcome->grades[$row->userid]->locked)) {
+                $select = '<select name="outcome_' . $index . '_' . $row->userid . '" class="quickgrade">';
+                foreach ($options as $optionindex => $optionvalue) {
+                    $selected = '';
+                    if ($outcome->grades[$row->userid]->grade == $optionindex) {
+                        $selected = 'selected="selected"';
+                    }
+                    $select .= '<option value="' . $optionindex . '"' . $selected . '>' . $optionvalue . '</option>';
+                }
+                $select .= '</select>';
+                $outcomes .= $this->output->container($outcome->name . ': ' . $select, 'outcome');
+            } else {
+                $outcomes .= $this->output->container($outcome->name . ': ' . $options[$outcome->grades[$row->userid]->grade], 'outcome');
+            }
         }
 
         return $outcomes;
@@ -284,7 +302,7 @@ class assign_grading_table extends table_sql implements renderable {
      * @return string
      */
     function col_select(stdClass $row) {
-        return '<input type="checkbox" name="selectedusers" value="' . $row->userid . '"/>';
+        return '<input type="checkbox" name="selectedusers" value="' . $row->userid . '" class="ignoredirty"/>';
     }
 
     /**
@@ -322,12 +340,7 @@ class assign_grading_table extends table_sql implements renderable {
             $separator = $this->output->spacer(array(), true);
         }
 
-
-        if ($row->grade) {
-            $grade = $this->display_grade($row->grade);
-        } else {
-            $grade = '-';
-        }
+        $grade = $this->display_grade($row->grade, $this->quickgrading, $row->userid, $row->timemarked);
 
 
         //return $grade . $separator . $link;
@@ -345,7 +358,7 @@ class assign_grading_table extends table_sql implements renderable {
 
         $grade = $this->get_gradebook_data_for_user($row->userid);
         if ($grade) {
-            $o = $this->display_grade($grade->grade);
+            $o = $this->display_grade($grade->grade, false, $row->userid, $row->timemarked);
         }
 
         return $o;
index b279a78..4141c42 100644 (file)
@@ -101,6 +101,8 @@ for <i>\'{$a->assignment}\'  at {$a->timeupdated}</i><br /><br />
 It is <a href="{$a->url}">available on the web site</a>.';
 $string['enabled'] = 'Enabled';
 $string['errornosubmissions'] = 'There are no submissions to download';
+$string['errorquickgradingnotcompatiblewithadvancedgrading'] = 'The grades were not saved because this assignment is currently using advanced grading';
+$string['errorrecordmodified'] = 'The grades were not saved because someone has modified one or more records more recently than when you loaded the page.';
 $string['feedbackcomments'] = 'Feedback comments';
 $string['feedback'] = 'Feedback';
 $string['feedbackplugins'] = 'Feedback plugins';
@@ -168,11 +170,16 @@ $string['preventlatesubmissions_help'] = 'If enabled, students will not be able
 $string['preventsubmissions'] = 'Prevent the user from making any more submissions to this assignment.';
 $string['preventsubmissionsshort'] = 'Prevent submission changes';
 $string['previous'] = 'Previous';
+$string['quickgrading'] = 'Quick grading';
+$string['quickgradingresult'] = 'Quick grading';
+$string['quickgradingchangessaved'] = 'The grade changes were saved';
+$string['quickgrading_help'] = 'Quick grading allows you to assign grades (and outcomes) directly in the submissions table. Quick grading is not compatible with advanced grading and is not recommended when there are multiple markers.';
 $string['reverttodraftforstudent'] = 'Revert submission to draft for student: (id={$a->id}, fullname={$a->fullname}).';
 $string['reverttodraft'] = 'Revert the submission to draft status.';
 $string['reverttodraftshort'] = 'Revert the submission to draft';
 $string['reviewed'] = 'Reviewed';
 $string['savechanges'] = 'Save changes';
+$string['saveallchanges'] = 'Save all changes';
 $string['savenext'] = 'Save and show next';
 $string['sendnotifications'] = 'Send notifications to graders';
 $string['sendnotifications_help'] = 'If enabled, graders (usually teachers) receive a message whenever a student submits an assignment, early, on time and late. Message methods are configurable.';
index 9cd960d..ddf8edc 100644 (file)
@@ -348,6 +348,9 @@ class assign {
                 //cancel button
                 $action = 'grading';
             }
+        }else if ($action == 'quickgrade') {
+            $message = $this->process_save_quick_grades();
+            $action = 'quickgradingresult';
         }else if ($action == 'saveoptions') {
             $this->process_save_grading_options();
             $action = 'grading';
@@ -360,6 +363,9 @@ class assign {
         if ($action == 'previousgrade') {
             $mform = null;
             $o .= $this->view_single_grade_page($mform, -1);
+        } else if ($action == 'quickgradingresult') {
+            $mform = null;
+            $o .= $this->view_quickgrading_result($message);
         } else if ($action == 'nextgrade') {
             $mform = null;
             $o .= $this->view_single_grade_page($mform, 1);
@@ -882,17 +888,20 @@ class assign {
      * Return a grade in user-friendly form, whether it's a scale or not
      *
      * @param mixed $grade int|null
+     * @param boolean $editing Are we allowing changes to this grade?
      * @return string User-friendly representation of grade
      */
-    public function display_grade($grade) {
+    public function display_grade($grade, $editing, $userid=0, $modified=0) {
         global $DB;
 
         static $scalegrades = array();
 
-
-
         if ($this->get_instance()->grade >= 0) {    // Normal number
-            if ($grade == -1 || $grade === null) {
+            if ($editing) {
+                $o = '<input type="text" name="quickgrade_' . $userid . '" value="' . $grade . '" size="6" maxlength="10" class="quickgrade"/>';
+                $o .= '&nbsp;/&nbsp;' . format_float($this->get_instance()->grade,2);
+                return $o;
+            } else if ($grade == -1 || $grade === null) {
                 return '-';
             } else {
                 return format_float(($grade),2) .'&nbsp;/&nbsp;'. format_float($this->get_instance()->grade,2);
@@ -906,11 +915,26 @@ class assign {
                     return '-';
                 }
             }
-            $scaleid = (int)$grade;
-            if (isset($this->cache['scale'][$scaleid])) {
-                return $this->cache['scale'][$scaleid];
+            if ($editing) {
+                $o = '<select name="quickgrade_' . $userid . '" class="quickgrade">';
+                $o .= '<option value="-1">' . get_string('nograde') . '</option>';
+                foreach ($this->cache['scale'] as $optionid => $option) {
+                    $selected = '';
+                    if ($grade == $optionid) {
+                        $selected = 'selected="selected"';
+                    }
+                    $o .= '<option value="' . $optionid . '" ' . $selected . '>' . $option . '</option>';
+                }
+                $o .= '</select>';
+                $o .= '<input type="hidden" name="grademodified_' . $userid . '" value="' . $modified . '"/>';
+                return $o;
+            } else {
+                $scaleid = (int)$grade;
+                if (isset($this->cache['scale'][$scaleid])) {
+                    return $this->cache['scale'][$scaleid];
+                }
+                return '-';
             }
-            return '-';
         }
     }
 
@@ -961,7 +985,7 @@ class assign {
      */
     private function get_grading_userid_list(){
         $filter = get_user_preferences('assign_filter', '');
-        $table = new assign_grading_table($this, 0, $filter);
+        $table = new assign_grading_table($this, 0, $filter, 0, false);
 
         $useridlist = $table->get_column_data('userid');
 
@@ -987,7 +1011,7 @@ class assign {
         }
 
         $filter = get_user_preferences('assign_filter', '');
-        $table = new assign_grading_table($this, 0, $filter);
+        $table = new assign_grading_table($this, 0, $filter, 0, false);
 
         $userid = $table->get_cell_data($num, 'userid', $last);
 
@@ -1203,11 +1227,28 @@ class assign {
         return $result;
     }
 
+    /**
+     * Display a grading error
+     *
+     * @param string $message - The description of the result
+     * @return string
+     */
+    private function view_quickgrading_result($message) {
+        $o = '';
+        $o .= $this->output->render(new assign_header($this->get_instance(),
+                                                      $this->get_context(),
+                                                      $this->show_intro(),
+                                                      $this->get_course_module()->id,
+                                                      get_string('quickgradingresult', 'assign')));
+        $o .= $this->output->render(new assign_quickgrading_result($message, $this->get_course_module()->id));
+        $o .= $this->view_footer();
+        return $o;
+    }
 
     /**
      * Display the page footer
      *
-     * @return None
+     * @return string
      */
     private function view_footer() {
         return $this->output->render_footer();
@@ -1523,6 +1564,7 @@ class assign {
         // Include grading options form
         require_once($CFG->dirroot . '/mod/assign/gradingoptionsform.php');
         require_once($CFG->dirroot . '/mod/assign/gradingactionsform.php');
+        require_once($CFG->dirroot . '/mod/assign/quickgradingform.php');
         require_once($CFG->dirroot . '/mod/assign/gradingbatchoperationsform.php');
         $o = '';
 
@@ -1548,13 +1590,25 @@ class assign {
                                                                   'post', '',
                                                                   array('class'=>'gradingactionsform'));
 
+        $gradingmanager = get_grading_manager($this->get_context(), 'mod_assign', 'submissions');
+
         $perpage = get_user_preferences('assign_perpage', 10);
         $filter = get_user_preferences('assign_filter', '');
+        $controller = $gradingmanager->get_active_controller();
+        $showquickgrading = empty($controller);
+        if (optional_param('action', '', PARAM_ALPHA) == 'saveoptions') {
+            $quickgrading = optional_param('quickgrading', false, PARAM_BOOL);
+            set_user_preference('assign_quickgrading', $quickgrading);
+        }
+        $quickgrading = get_user_preferences('assign_quickgrading', false);
+
         // print options  for changing the filter and changing the number of results per page
         $gradingoptionsform = new mod_assign_grading_options_form(null,
                                                                   array('cm'=>$this->get_course_module()->id,
                                                                         'contextid'=>$this->context->id,
-                                                                        'userid'=>$USER->id),
+                                                                        'userid'=>$USER->id,
+                                                                        'showquickgrading'=>$showquickgrading,
+                                                                        'quickgrading'=>$quickgrading),
                                                                   'post', '',
                                                                   array('class'=>'gradingoptionsform'));
 
@@ -1577,10 +1631,18 @@ class assign {
         }
 
         $o .= $this->output->render(new assign_form('gradingactionsform', $gradingactionsform));
-        $o .= $this->output->render(new assign_form('gradingoptionsform', $gradingoptionsform));
+        $o .= $this->output->render(new assign_form('gradingoptionsform', $gradingoptionsform, 'M.mod_assign.init_grading_options'));
 
         // load and print the table of submissions
-        $o .= $this->output->render(new assign_grading_table($this, $perpage, $filter));
+        if ($showquickgrading && $quickgrading) {
+            $table = $this->output->render(new assign_grading_table($this, $perpage, $filter, 0, true));
+            $quickgradingform = new mod_assign_quick_grading_form(null,
+                                                                  array('cm'=>$this->get_course_module()->id,
+                                                                        'gradingtable'=>$table));
+            $o .= $this->output->render(new assign_form('quickgradingform', $quickgradingform));
+        } else {
+            $o .= $this->output->render(new assign_grading_table($this, $perpage, $filter, 0, false));
+        }
 
         $currentgroup = groups_get_activity_group($this->get_course_module(), true);
         $users = array_keys($this->list_participants($currentgroup, true));
@@ -1658,7 +1720,7 @@ class assign {
                                                       $this->get_course_module()->id,
                                                       get_string('editsubmission', 'assign')));
 
-        $o .= $this->output->notification('This assignment is no longer accepting submissions');
+        $o .= $this->output->notification(get_string('submissionsclosed', 'assign'));
 
         $o .= $this->view_footer();
 
@@ -1682,9 +1744,7 @@ class assign {
         require_capability('mod/assign:submit', $this->context);
 
         if (!$this->submissions_open()) {
-            $subclosed  = '';
-            $subclosed .= $this->view_student_error_message();
-            return $subclosed;
+            return $this->view_student_error_message();
         }
         $o .= $this->output->render(new assign_header($this->get_instance(),
                                                       $this->get_context(),
@@ -1875,7 +1935,7 @@ class assign {
                                                                  $gradebookgrade->str_long_grade,
                                                                  has_capability('mod/assign:grade', $this->get_context()));
                 } else {
-                    $gradefordisplay = $this->display_grade($gradebookgrade->grade);
+                    $gradefordisplay = $this->display_grade($gradebookgrade->grade, false);
                 }
 
                 $gradeddate = $gradebookgrade->dategraded;
@@ -2256,6 +2316,118 @@ class assign {
         }
     }
 
+    /**
+     * save quick grades
+     *
+     * @return string - The result of the save operation
+     */
+    private function process_save_quick_grades() {
+        global $USER, $DB, $CFG;
+
+        // Need grade permission
+        require_capability('mod/assign:grade', $this->context);
+
+        // make sure advanced grading is disabled
+        $gradingmanager = get_grading_manager($this->get_context(), 'mod_assign', 'submissions');
+        $controller = $gradingmanager->get_active_controller();
+        if (!empty($controller)) {
+            return get_string('errorquickgradingnotcompatiblewithadvancedgrading', 'assign');
+        }
+
+        $users = array();
+        // first check all the last modified values
+        $len = strlen('grademodified_');
+        foreach ($_POST as $key => $value) {
+            if (substr($key, 0, $len) === 'grademodified_') {
+                // gather the userid, updated grade and last modified value
+                $record = new stdClass();
+                $record->userid = (int)substr($key, $len);
+                $record->grade = required_param('quickgrade_' . $record->userid, PARAM_INT);
+                $record->lastmodified = $value;
+                $record->gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, array($record->userid));
+                $users[$record->userid] = $record;
+            }
+        }
+        list($userids, $useridparams) = $DB->get_in_or_equal(array_keys($users));
+
+        // check them all for currency
+        $currentgrades = $DB->get_recordset_sql('SELECT u.id as userid,
+                                                        g.grade as grade,
+                                                        g.timemodified as lastmodified
+                                                 FROM {user} u
+                                                 LEFT JOIN {assign_grades} g ON
+                                                            u.id = g.userid AND
+                                                            g.assignment = ? WHERE u.id ' .
+                                                 $userids,
+                                                 array_merge(array($this->get_instance()->id),
+                                                       $useridparams));
+
+        $modifiedusers = array();
+        foreach ($currentgrades as $current) {
+            $modified = $users[(int)$current->userid];
+
+            // check to see if the outcomes were modified
+            if ($CFG->enableoutcomes) {
+                foreach ($modified->gradinginfo->outcomes as $outcomeid => $outcome) {
+                    $oldoutcome = $outcome->grades[$modified->userid]->grade;
+                    $newoutcome = optional_param('outcome_' . $outcomeid . '_' . $modified->userid, -1, PARAM_INT);
+                    if ($oldoutcome != $newoutcome) {
+                        // can't check modified time for outcomes because it is not reported
+                        $modifiedusers[$modified->userid] = $modified;
+                        continue;
+                    }
+                }
+            }
+
+
+            if (($current->grade < 0 || $current->grade === NULL) &&
+                ($modified->grade < 0 || $modified->grade === NULL)) {
+                // different ways to indicate no grade
+                continue;
+            }
+            if ($current->grade != $modified->grade) {
+                // grade changed
+                if ((int)$current->lastmodified > (int)$modified->lastmodified) {
+                    // error - record has been modified since viewing the page
+                    return get_string('errorrecordmodified', 'assign');
+                } else {
+                    $modifiedusers[$modified->userid] = $modified;
+                }
+            }
+
+        }
+
+        // ok - ready to process the updates
+        foreach ($modifiedusers as $userid => $modified) {
+            $grade = $this->get_user_grade($userid, true);
+            $grade->grade= grade_floatval($modified->grade);
+            $grade->grader= $USER->id;
+
+            $this->update_grade($grade);
+
+            // save outcomes
+            if ($CFG->enableoutcomes) {
+                $data = array();
+                foreach ($modified->gradinginfo->outcomes as $outcomeid => $outcome) {
+                    $oldoutcome = $outcome->grades[$modified->userid]->grade;
+                    $newoutcome = optional_param('outcome_' . $outcomeid . '_' . $modified->userid, -1, PARAM_INT);
+                    if ($oldoutcome != $newoutcome) {
+                        $data[$outcomeid] = $newoutcome;
+                    }
+                }
+                if (count($data) > 0) {
+                    grade_update_outcomes('mod/assign', $this->course->id, 'mod', 'assign', $this->get_instance()->id, $userid, $data);
+                }
+            }
+
+            $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
+
+            $this->add_to_log('grade submission', $this->format_grade_for_log($grade));
+        }
+
+        return get_string('quickgradingchangessaved', 'assign');
+    }
+
     /**
      * save grading options
      *
@@ -2272,7 +2444,7 @@ class assign {
 
 
 
-        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id));
+        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id, 'showquickgrading'=>false));
 
         if ($formdata = $mform->get_data()) {
             set_user_preference('assign_perpage', $formdata->perpage);
@@ -2295,7 +2467,7 @@ class assign {
 
         $info = get_string('gradestudent', 'assign', array('id'=>$user->id, 'fullname'=>fullname($user)));
         if ($grade->grade != '') {
-            $info .= get_string('grade') . ': ' . $this->display_grade($grade->grade) . '. ';
+            $info .= get_string('grade') . ': ' . $this->display_grade($grade->grade, false) . '. ';
         } else {
             $info .= get_string('nograde', 'assign');
         }
index 386a117..841da27 100644 (file)
@@ -39,23 +39,25 @@ M.mod_assign.init_grading_table = function(Y) {
         });
 
         var selectall = Y.one('th.c0 input');
-        selectall.on('change', function(e) {
-            if (e.currentTarget.get('checked')) {
-                checkboxes = Y.all('td.c0 input');
-                checkboxes.each(function(node) {
-                    rowelement = node.get('parentNode').get('parentNode');
-                    node.set('checked', true);
-                    rowelement.setAttribute('class', 'selectedrow');
-                });
-            } else {
-                checkboxes = Y.all('td.c0 input');
-                checkboxes.each(function(node) {
-                    rowelement = node.get('parentNode').get('parentNode');
-                    node.set('checked', false);
-                    rowelement.setAttribute('class', 'unselectedrow');
-                });
-            }
-        });
+        if (selectall) {
+            selectall.on('change', function(e) {
+                if (e.currentTarget.get('checked')) {
+                    checkboxes = Y.all('td.c0 input');
+                    checkboxes.each(function(node) {
+                        rowelement = node.get('parentNode').get('parentNode');
+                        node.set('checked', true);
+                        rowelement.setAttribute('class', 'selectedrow');
+                    });
+                } else {
+                    checkboxes = Y.all('td.c0 input');
+                    checkboxes.each(function(node) {
+                        rowelement = node.get('parentNode').get('parentNode');
+                        node.set('checked', false);
+                        rowelement.setAttribute('class', 'unselectedrow');
+                    });
+                }
+            });
+        }
 
         var batchform = Y.one('form.gradingbatchoperationsform');
         batchform.on('submit', function(e) {
@@ -99,8 +101,72 @@ M.mod_assign.init_grading_table = function(Y) {
 
 
         });
+        quickgrade = Y.all('.gradingtable .quickgrade');
+        quickgrade.each(function(quick) {
+            quick.on('change', function(e) {
+                parent = this.get('parentNode');
+                parent.addClass('quickgrademodified');
+            });
+        });
+    });
+};
+
+M.mod_assign.check_dirty_quickgrading_form = function(e) {
+
+            if (!M.core_formchangechecker.get_form_dirty_state()) {
+                // the form is not dirty, so don't display any message
+                return;
+            }
+
+            // This is the error message that we'll show to browsers which support it
+            var warningmessage = 'There are unsaved quickgrading changes. Do you really wanto to leave this page?';
+
+            // Most browsers are happy with the returnValue being set on the event
+            // But some browsers do not consistently pass the event
+            if (e) {
+                e.returnValue = warningmessage;
+            }
+
+            // But some require it to be returned instead
+            return warningmessage;
+}
+M.mod_assign.init_grading_options = function(Y) {
+    Y.use('node', function(Y) {
+
+        var paginationelement = Y.one('#id_perpage');
+        paginationelement.on('change', function(e) {
+            Y.one('form.gradingoptionsform').submit();
+        });
+        var filterelement = Y.one('#id_filter');
+        filterelement.on('change', function(e) {
+            Y.one('form.gradingoptionsform').submit();
+        });
+        var quickgradingelement = Y.one('#id_quickgrading');
+        quickgradingelement.on('change', function(e) {
+            Y.one('form.gradingoptionsform').submit();
+        });
 
     });
 
 
 };
+// override the default dirty form behaviour to ignore any input with the class "ignoredirty"
+M.mod_assign.set_form_changed = M.core_formchangechecker.set_form_changed;
+M.core_formchangechecker.set_form_changed = function(e) {
+    target = e.currentTarget;
+    if (!target.hasClass('ignoredirty')) {
+        M.mod_assign.set_form_changed(e);
+    }
+}
+
+M.mod_assign.get_form_dirty_state = M.core_formchangechecker.get_form_dirty_state;
+M.core_formchangechecker.get_form_dirty_state = function() {
+    var state = M.core_formchangechecker.stateinformation;
+    if (state.focused_element) {
+        if (state.focused_element.element.hasClass('ignoredirty')) {
+            state.focused_element.initial_value = state.focused_element.element.get('value')
+        }
+    }
+    return M.mod_assign.get_form_dirty_state();
+}
+
diff --git a/mod/assign/quickgradingform.php b/mod/assign/quickgradingform.php
new file mode 100644 (file)
index 0000000..0598b57
--- /dev/null
@@ -0,0 +1,62 @@
+<?php
+// 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/>.
+
+/**
+ * This file contains the forms to create and edit an instance of this module
+ *
+ * @package   mod_assign
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
+
+
+/** Include formslib.php */
+require_once ($CFG->libdir.'/formslib.php');
+/** Include locallib.php */
+require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+/**
+ * Assignment quick grading form
+ *
+ * @package   mod_assign
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mod_assign_quick_grading_form extends moodleform {
+    /**
+     * Define this form - called from the parent constructor
+     */
+    function definition() {
+        $mform = $this->_form;
+        $instance = $this->_customdata;
+
+        // visible elements
+        $mform->addElement('html', $instance['gradingtable']);
+
+        // hidden params
+        $mform->addElement('hidden', 'id', $instance['cm']);
+        $mform->setType('id', PARAM_INT);
+        $mform->addElement('hidden', 'action', 'quickgrade');
+        $mform->setType('action', PARAM_ALPHA);
+
+        // buttons
+        $mform->addElement('header', 'general', get_string('quickgrading', 'assign'));
+        $mform->addElement('submit', 'savequickgrades', get_string('saveallchanges', 'assign'));
+    }
+}
+
index 6ce054c..fa7a9fe 100644 (file)
@@ -48,6 +48,29 @@ class assign_submit_for_grading_page implements renderable {
 
 }
 
+/**
+ * Implements a renderable grading error notification
+ * @package   mod_assign
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class assign_quickgrading_result implements renderable {
+    /** @var string $message is the message to display to the user */
+    var $message = '';
+    /** @var int $coursemoduleid */
+    var $coursemoduleid = 0;
+
+    /**
+     * Constructor
+     * @param string $message This is the message to display
+     */
+    public function __construct($message, $coursemoduleid) {
+        $this->message = $message;
+        $this->coursemoduleid = $coursemoduleid;
+    }
+
+}
+
 /**
  * Implements a renderable grading options form
  * @package   mod_assign
@@ -59,19 +82,24 @@ class assign_form implements renderable {
     var $form = null;
     /** @var string $classname is the name of the class to assign to the container */
     var $classname = '';
+    /** @var string $jsinitfunction is an optional js function to add to the page requires */
+    var $jsinitfunction = '';
 
     /**
      * Constructor
-     * @param string $classname
-     * @param moodleform $form
+     * @param string $classname This is the class name for the container div
+     * @param moodleform $form This is the moodleform
+     * @param string $jsinitfunction This is an optional js function to add to the page requires
      */
-    public function __construct($classname, moodleform $form) {
+    public function __construct($classname, moodleform $form, $jsinitfunction = '') {
         $this->classname = $classname;
         $this->form = $form;
+        $this->jsinitfunction = $jsinitfunction;
     }
 
 }
 
+
 /**
  * Implements a renderable user summary
  * @package   mod_assign
index 8fca9b0..7efed66 100644 (file)
@@ -86,6 +86,24 @@ class mod_assign_renderer extends plugin_renderer_base {
         $table->data[] = $row;
     }
 
+    /**
+     * Render a grading error notification
+     * @param assign_quickgrading_result $result The result to render
+     * @return string
+     */
+    public function render_assign_quickgrading_result(assign_quickgrading_result $result) {
+        $o = '';
+        $o .= $this->output->heading(get_string('quickgradingresult', 'assign'), 4);
+
+        $o .= $this->output->notification($result->message);
+
+        $o .= $this->output->continue_button(new moodle_url('/mod/assign/view.php',
+                                                          array('id' => $result->coursemoduleid,
+                                                                'action'=>'grading')));
+
+        return $o;
+    }
+
     /**
      * Render the generic form
      * @param assign_form $form The form to render
@@ -93,6 +111,9 @@ class mod_assign_renderer extends plugin_renderer_base {
      */
     public function render_assign_form(assign_form $form) {
         $o = '';
+        if ($form->jsinitfunction) {
+            $this->page->requires->js_init_call($form->jsinitfunction, array());
+        }
         $o .= $this->output->box_start('boxaligncenter ' . $form->classname);
         $o .= $this->moodleform($form->form);
         $o .= $this->output->box_end();
index 55523a9..de28899 100644 (file)
@@ -128,3 +128,7 @@ div.earlysubmission {
     border: 0px;
 }
 
+#page-mod-assign-view div.gradingtable tr .quickgrademodified {
+    background-color: #FFCC99;
+}
+