Merge branch 'MDL-37563-23' of git://github.com/damyon/moodle into MOODLE_23_STABLE
authorSam Hemelryk <sam@moodle.com>
Mon, 21 Jan 2013 20:10:23 +0000 (09:10 +1300)
committerSam Hemelryk <sam@moodle.com>
Mon, 21 Jan 2013 20:10:23 +0000 (09:10 +1300)
21 files changed:
course/lib.php
enrol/locallib.php
files/renderer.php
grade/report/grader/lib.php
grade/report/grader/styles.css
install/lang/zh_tw/install.php
lib/blocklib.php
lib/form/filemanager.js
lib/javascript-static.js
lib/tests/weblib_test.php
lib/weblib.php
login/index.php
login/index_form.html
mod/assign/lib.php
mod/forum/backup/moodle2/restore_forum_activity_task.class.php
mod/lesson/locallib.php
mod/lesson/pagetypes/matching.php
mod/quiz/cronlib.php
mod/quiz/locallib.php
mod/scorm/locallib.php
version.php

index bbb855e..21cd265 100644 (file)
@@ -2879,6 +2879,13 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
         return false;
     }
+
+    // Create events and propagate visibility to associated grade items if the value has changed.
+    // Only do this if it's changed to avoid accidently overwriting manual showing/hiding of student grades.
+    if ($cm->visible == $visible) {
+        return true;
+    }
+
     if (!$modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
         return false;
     }
@@ -2892,7 +2899,7 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
         }
     }
 
-    // hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there
+    // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
     $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
     if ($grade_items) {
         foreach ($grade_items as $grade_item) {
index e923c2e..1577265 100644 (file)
@@ -792,7 +792,9 @@ class course_enrolment_manager {
                         break;
                 }
             }
-            $users[$userrole->id]['roles'] = array();
+            if (!isset($users[$userrole->id]['roles'])) {
+                $users[$userrole->id]['roles'] = array();
+            }
             $users[$userrole->id]['roles'][$userrole->roleid] = array(
                 'text' => $roletext,
                 'unchangeable' => !$changeable
index 4c6dc8b..9fc233c 100644 (file)
@@ -304,7 +304,10 @@ class core_files_renderer extends plugin_renderer_base {
     private function fm_js_template_mkdir() {
         $rv = '
 <div class="filemanager fp-mkdir-dlg">
-    <div class="fp-mkdir-dlg-text">'.get_string('newfoldername','repository').'<br/><input type="text" /></div>
+    <div class="fp-mkdir-dlg-text">
+        <label>' . get_string('newfoldername', 'repository') . '</label><br/>
+        <input type="text" />
+    </div>
     <button class="{!}fp-dlg-butcreate">'.get_string('makeafolder').'</button>
     <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
 </div>';
index 3b4cc42..9f0eabb 100644 (file)
@@ -181,7 +181,7 @@ class grade_report_grader extends grade_report {
         // Were any changes made?
         $changedgrades = false;
 
-        foreach ($data as $varname => $postedvalue) {
+        foreach ($data as $varname => $students) {
 
             $needsupdate = false;
 
@@ -194,113 +194,116 @@ class grade_report_grader extends grade_report {
                 continue;
             }
 
-            $gradeinfo = explode("_", $varname);
-            $userid = clean_param($gradeinfo[1], PARAM_INT);
-            $itemid = clean_param($gradeinfo[2], PARAM_INT);
+            foreach ($students as $userid => $items) {
+                $userid = clean_param($userid, PARAM_INT);
+                foreach ($items as $itemid => $postedvalue) {
+                    $itemid = clean_param($itemid, PARAM_INT);
+
+                    // Was change requested?
+                    $oldvalue = $this->grades[$userid][$itemid];
+                    if ($datatype === 'grade') {
+                        // If there was no grade and there still isn't
+                        if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
+                            // -1 means no grade
+                            continue;
+                        }
 
-            // Was change requested?
-            $oldvalue = $this->grades[$userid][$itemid];
-            if ($datatype === 'grade') {
-                // If there was no grade and there still isn't
-                if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
-                    // -1 means no grade
-                    continue;
-                }
+                        // If the grade item uses a custom scale
+                        if (!empty($oldvalue->grade_item->scaleid)) {
 
-                // If the grade item uses a custom scale
-                if (!empty($oldvalue->grade_item->scaleid)) {
+                            if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
+                                continue;
+                            }
+                        } else {
+                            // The grade item uses a numeric scale
 
-                    if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
-                        continue;
-                    }
-                } else {
-                    // The grade item uses a numeric scale
+                            // Format the finalgrade from the DB so that it matches the grade from the client
+                            if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
+                                continue;
+                            }
+                        }
 
-                    // Format the finalgrade from the DB so that it matches the grade from the client
-                    if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
-                        continue;
+                        $changedgrades = true;
+
+                    } else if ($datatype === 'feedback') {
+                        if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
+                            continue;
+                        }
                     }
-                }
 
-                $changedgrades = true;
+                    if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) {
+                        print_error('invalidgradeitemid');
+                    }
 
-            } else if ($datatype === 'feedback') {
-                if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
-                    continue;
-                }
-            }
+                    // Pre-process grade
+                    if ($datatype == 'grade') {
+                        $feedback = false;
+                        $feedbackformat = false;
+                        if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
+                            if ($postedvalue == -1) { // -1 means no grade
+                                $finalgrade = null;
+                            } else {
+                                $finalgrade = $postedvalue;
+                            }
+                        } else {
+                            $finalgrade = unformat_float($postedvalue);
+                        }
 
-            if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) { // we must verify course id here!
-                print_error('invalidgradeitemid');
-            }
+                        $errorstr = '';
+                        // Warn if the grade is out of bounds.
+                        if (is_null($finalgrade)) {
+                            // ok
+                        } else {
+                            $bounded = $gradeitem->bounded_grade($finalgrade);
+                            if ($bounded > $finalgrade) {
+                            $errorstr = 'lessthanmin';
+                            } else if ($bounded < $finalgrade) {
+                                $errorstr = 'morethanmax';
+                            }
+                        }
+                        if ($errorstr) {
+                            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
+                            $gradestr = new stdClass();
+                            $gradestr->username = fullname($user);
+                            $gradestr->itemname = $gradeitem->get_name();
+                            $warnings[] = get_string($errorstr, 'grades', $gradestr);
+                        }
 
-            // Pre-process grade
-            if ($datatype == 'grade') {
-                $feedback = false;
-                $feedbackformat = false;
-                if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
-                    if ($postedvalue == -1) { // -1 means no grade
-                        $finalgrade = null;
-                    } else {
-                        $finalgrade = $postedvalue;
+                    } else if ($datatype == 'feedback') {
+                        $finalgrade = false;
+                        $trimmed = trim($postedvalue);
+                        if (empty($trimmed)) {
+                             $feedback = NULL;
+                        } else {
+                             $feedback = $postedvalue;
+                        }
                     }
-                } else {
-                    $finalgrade = unformat_float($postedvalue);
-                }
 
-                $errorstr = '';
-                // Warn if the grade is out of bounds.
-                if (is_null($finalgrade)) {
-                    // ok
-                } else {
-                    $bounded = $gradeitem->bounded_grade($finalgrade);
-                    if ($bounded > $finalgrade) {
-                    $errorstr = 'lessthanmin';
-                    } else if ($bounded < $finalgrade) {
-                        $errorstr = 'morethanmax';
+                    // group access control
+                    if ($separategroups) {
+                        // note: we can not use $this->currentgroup because it would fail badly
+                        //       when having two browser windows each with different group
+                        $sharinggroup = false;
+                        foreach($mygroups as $groupid) {
+                            if (groups_is_member($groupid, $userid)) {
+                                $sharinggroup = true;
+                                break;
+                            }
+                        }
+                        if (!$sharinggroup) {
+                            // either group membership changed or somebody is hacking grades of other group
+                            $warnings[] = get_string('errorsavegrade', 'grades');
+                            continue;
+                        }
                     }
-                }
-                if ($errorstr) {
-                    $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
-                    $gradestr = new stdClass();
-                    $gradestr->username = fullname($user);
-                    $gradestr->itemname = $gradeitem->get_name();
-                    $warnings[] = get_string($errorstr, 'grades', $gradestr);
-                }
 
-            } else if ($datatype == 'feedback') {
-                $finalgrade = false;
-                $trimmed = trim($postedvalue);
-                if (empty($trimmed)) {
-                     $feedback = NULL;
-                } else {
-                     $feedback = $postedvalue;
-                }
-            }
+                    $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
 
-            // group access control
-            if ($separategroups) {
-                // note: we can not use $this->currentgroup because it would fail badly
-                //       when having two browser windows each with different group
-                $sharinggroup = false;
-                foreach($mygroups as $groupid) {
-                    if (groups_is_member($groupid, $userid)) {
-                        $sharinggroup = true;
-                        break;
+                    // We can update feedback without reloading the grade item as it doesn't affect grade calculations
+                    if ($datatype === 'feedback') {
+                        $this->grades[$userid][$itemid]->feedback = $feedback;
                     }
                 }
-                if (!$sharinggroup) {
-                    // either group membership changed or somebody is hacking grades of other group
-                    $warnings[] = get_string('errorsavegrade', 'grades');
-                    continue;
-                }
-            }
-
-            $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
-
-            // We can update feedback without reloading the grade item as it doesn't affect grade calculations
-            if ($datatype === 'feedback') {
-                $this->grades[$userid][$itemid]->feedback = $feedback;
             }
         }
 
@@ -1017,7 +1020,7 @@ class grade_report_grader extends grade_report {
                             }
                             $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
                             $itemcell->text .= html_writer::label(get_string('typescale', 'grades'), $attributes['id'], false, array('class' => 'accesshide'));
-                            $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);
+                            $itemcell->text .= html_writer::select($scaleopt, 'grade['.$userid.']['.$item->id.']', $gradeval, array(-1=>$nogradestr), $attributes);
                         } elseif(!empty($scale)) {
                             $scales = explode(",", $scale->scale);
 
@@ -1036,8 +1039,8 @@ class grade_report_grader extends grade_report {
                         if ($this->get_pref('quickgrading') and $grade->is_editable()) {
                             $value = format_float($gradeval, $decimalpoints);
                             $itemcell->text .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade']
-                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade_'
-                                          .$userid.'_' .$item->id.'" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
+                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade['
+                                          .$userid.'][' .$item->id.']" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
                         } else {
                             $itemcell->text .= html_writer::tag('span', format_float($gradeval, $decimalpoints), array('class'=>"gradevalue$hidden$gradepass"));
                         }
@@ -1048,7 +1051,7 @@ class grade_report_grader extends grade_report {
                     if ($this->get_pref('showquickfeedback') and $grade->is_editable()) {
 
                         $itemcell->text .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'].'" id="feedback_'.$userid.'_'.$item->id
-                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_'.$userid.'_'.$item->id.'" value="' . s($grade->feedback) . '" />';
+                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback['.$userid.']['.$item->id.']" value="' . s($grade->feedback) . '" />';
                     }
 
                 } else { // Not editing
@@ -1730,25 +1733,21 @@ class grade_report_grader extends grade_report {
             // Will this number of students result in more fields that we are allowed?
             $maxinputvars = ini_get('max_input_vars');
             if ($maxinputvars !== false) {
-                $fieldspergradeitem = 0; // The number of fields output per grade item for each student
+                // We can't do anything about there being more grade items than max_input_vars,
+                // but we can decrease number of students per page if there are >= max_input_vars
+                $fieldsperstudent = 0; // The number of fields output per student
 
-                if ($this->get_pref('quickgrading')) {
-                    // One grade field
-                    $fieldspergradeitem ++;
-                }
-                if ($this->get_pref('showquickfeedback')) {
-                    // One feedback field
-                    $fieldspergradeitem ++;
+                if ($this->get_pref('quickgrading') || $this->get_pref('showquickfeedback')) {
+                    // Each array (grade, feedback) will gain one element
+                    $fieldsperstudent ++;
                 }
 
-                $fieldsperstudent = $fieldspergradeitem * count($this->gtree->get_items());
                 $fieldsrequired = $studentsperpage * $fieldsperstudent;
-                if ($fieldsrequired > $maxinputvars) {
-                    $studentsperpage = floor($maxinputvars / $fieldsperstudent);
+                if ($fieldsrequired >= $maxinputvars) {
+                    $studentsperpage = $maxinputvars - 1; // Subtract one to be on the safe side
                     if ($studentsperpage<1) {
-                        // Make sure students per page doesn't fall below 1
-                        // PHP max_input_vars could potentially be reached with 1 student
-                        // if there are >500 grade items and quickgrading and showquickfeedback are on
+                        // Make sure students per page doesn't fall below 1, though if your
+                        // max_input_vars is only 1 you've got bigger problems!
                         $studentsperpage = 1;
                     }
 
index 2babb4e..3652d71 100644 (file)
@@ -578,7 +578,7 @@ background-color:#f3ead8;
     vertical-align:middle;
 }
 
-.path-grade-report-grader .yui-overlay {
+.path-grade-report-grader .yui3-overlay {
     background-color: #FFEE69;
     border-color: #D4C237 #A6982B #A6982B;
     border-style: solid;
@@ -588,15 +588,15 @@ background-color:#f3ead8;
     font-size: 0.7em;
 }
 
-.path-grade-report-grader .yui-overlay .fullname {
+.path-grade-report-grader .yui3-overlay .fullname {
     color: #5F3E00;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .itemname {
+.path-grade-report-grader .yui3-overlay .itemname {
     color: #194F3E;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .feedback {
+.path-grade-report-grader .yui3-overlay .feedback {
     color: #5F595E;
 }
 /* table#user-grades td */
@@ -605,7 +605,7 @@ background-color:#f3ead8;
   text-align: left;
 }
 
-.path-grade-report-grader .yui-overlay a.container-close {
+.path-grade-report-grader .yui3-overlay a.container-close {
   margin-top: -3px;
 }
 
index ddfffbe..db31bba 100644 (file)
@@ -73,9 +73,9 @@ $string['pathsunsecuredataroot'] = '資料根(Dataroot)目錄的位置不安全'
 $string['pathswrongadmindir'] = '管理目錄不存在';
 $string['phpextension'] = '{$a} PHP擴展';
 $string['phpversion'] = 'PHP版本';
-$string['phpversionhelp'] = '<p>Moodle 需要至少4.1.0.的PHP版本 </p>
+$string['phpversionhelp'] = '<p>Moodle 需要的PHP版本至少要4.3.0或是5.1.0 (5.0.x有一些已知的問題)  </p>
 <p>您目前執行的是{$a} 版</p>
-<p>您必須更新您的 PHP 或在有更新版本的主機進行安裝!</p>';
+<p>您必須更新您的 PHP 或在有更新版本的主機進行安裝!!(若是5.0.x,你可以下降到4.4.x 版本)</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['welcomep20'] = '這個頁面是提醒您已經成功安裝與啟動 <strong>{$a->packname} {$a->packversion}</strong> ,恭喜!';
 $string['welcomep30'] = '<strong>{$a->installername}</strong>包含了可以建立<strong>Moodle</strong>執行環境的應用程序:';
index c893a95..97d3802 100644 (file)
@@ -1068,7 +1068,7 @@ class block_manager {
 
             $controls[] = array('url' => $CFG->wwwroot . '/' . $CFG->admin .
                     '/roles/assign.php?contextid=' . $block->context->id . '&returnurl=' . urlencode($return),
-                    'icon' => 't/roles', 'caption' => get_string('assignrolesinblock', 'block', $block->title),
+                    'icon' => 'i/roles', 'caption' => get_string('assignrolesinblock', 'block', $block->title),
                     'class' => 'editing_roles');
         }
 
index 21b4689..9e825e3 100644 (file)
@@ -316,6 +316,7 @@ M.form_filemanager.init = function(Y, options) {
                             on('keydown', function(e){
                                 if (e.keyCode == 13) {Y.bind(perform_action, this)(e);}
                             }, this);
+                        node.one('label').set('for', 'fm-newname-' + this.client_id);
                         node.all('.fp-dlg-butcancel').on('click', function(e){e.preventDefault();this.mkdir_dialog.hide();}, this);
                         node.all('.fp-dlg-curpath').set('id', 'fm-curpath-'+this.client_id);
                     }
index 858fe24..5d6f4ee 100644 (file)
@@ -813,6 +813,16 @@ M.util.focus_login_form = function(Y) {
     }
 }
 
+/**
+ * Set focus on login error message
+ */
+M.util.focus_login_error = function(Y) {
+    var errorlog = Y.one('#loginerrormessage');
+
+    if (errorlog) {
+        errorlog.focus();
+    }
+}
 /**
  * Adds lightbox hidden element that covers the whole node.
  *
index c5a75c8..4ac75de 100644 (file)
@@ -179,8 +179,23 @@ class web_testcase extends advanced_testcase {
     }
 
     function test_out_as_local_url() {
+        global $CFG;
+        // Test http url.
         $url1 = new moodle_url('/lib/tests/weblib_test.php');
         $this->assertEquals('/lib/tests/weblib_test.php', $url1->out_as_local_url());
+
+        // Test https url.
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+        $url2 = new moodle_url($httpswwwroot.'/login/profile.php');
+        $this->assertEquals('/login/profile.php', $url2->out_as_local_url());
+
+        // Test http url matching wwwroot.
+        $url3 = new moodle_url($CFG->wwwroot);
+        $this->assertEquals('', $url3->out_as_local_url());
+
+        // Test http url matching wwwroot ending with slash (/).
+        $url3 = new moodle_url($CFG->wwwroot.'/');
+        $this->assertEquals('/', $url3->out_as_local_url());
     }
 
     /**
@@ -192,6 +207,31 @@ class web_testcase extends advanced_testcase {
         $url2->out_as_local_url();
     }
 
+    /**
+     * You should get error with modified url
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_modified_url_out_as_local_url_error() {
+        global $CFG;
+
+        $modifiedurl = $CFG->wwwroot.'1';
+        $url3 = new moodle_url($modifiedurl.'/login/profile.php');
+        $url3->out_as_local_url();
+    }
+
+    /**
+     * Try get local url from external https url and you should get error
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_https_out_as_local_url_error() {
+        $url4 = new moodle_url('https://www.google.com/lib/tests/weblib_test.php');
+        $url4->out_as_local_url();
+    }
+
     public function test_clean_text() {
         $text = "lala <applet>xx</applet>";
         $this->assertEquals($text, clean_text($text, FORMAT_PLAIN));
index 500467b..6c8ebab 100644 (file)
@@ -747,12 +747,18 @@ class moodle_url {
         global $CFG;
 
         $url = $this->out($escaped, $overrideparams);
-
-        if (strpos($url, $CFG->wwwroot) !== 0) {
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+
+        // $url should be equal to wwwroot or httpswwwroot. If not then throw exception.
+        if (($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($CFG->wwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else if (($url === $httpswwwroot) || (strpos($url, $httpswwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($httpswwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else {
             throw new coding_exception('out_as_local_url called on a non-local URL');
         }
-
-        return str_replace($CFG->wwwroot, '', $url);
     }
 
     /**
index 1847544..4526ba6 100644 (file)
@@ -345,7 +345,9 @@ if (isloggedin() and !isguestuser()) {
     echo $OUTPUT->box_end();
 } else {
     include("index_form.html");
-    if (!empty($CFG->loginpageautofocus)) {
+    if ($errormsg) {
+        $PAGE->requires->js_init_call('M.util.focus_login_error', null, true);
+    } else if (!empty($CFG->loginpageautofocus)) {
         //focus username or password
         $PAGE->requires->js_init_call('M.util.focus_login_form', null, true);
     }
index 1765064..f7557a5 100644 (file)
@@ -30,9 +30,10 @@ if (empty($CFG->xmlstrictheaders) and !empty($CFG->loginpasswordautocomplete)) {
         </div>
         <?php
           if (!empty($errormsg)) {
-              echo '<div class="loginerrors">';
+              echo html_writer::start_tag('div', array('class' => 'loginerrors'));
+              echo html_writer::link('#', $errormsg, array('id' => 'loginerrormessage', 'class' => 'accesshide'));
               echo $OUTPUT->error_text($errormsg);
-              echo '</div>';
+              echo html_writer::end_tag('div');
           }
         ?>
         <form action="<?php echo $CFG->httpswwwroot; ?>/login/index.php" method="post" id="login" <?php echo $autocomplete; ?> >
index 92490ec..bc0e118 100644 (file)
@@ -326,7 +326,7 @@ function assign_print_overview($courses, &$htmlarray) {
     // get all user submissions, indexed by assignment id
     $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS nosubmissions, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
                             FROM {assign} a LEFT JOIN {assign_grades} g ON g.assignment = a.id AND g.userid = ? LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = ?
-                            AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
+                            WHERE a.id $sqlassignmentids", array($USER->id, $USER->id));
 
     foreach ($assignments as $assignment) {
         // Do not show assignments that are not open
index ea00ab2..903c9a1 100644 (file)
@@ -112,6 +112,7 @@ class restore_forum_activity_task extends restore_activity_task {
         $rules[] = new restore_log_rule('forum', 'delete discussion', 'view.php?id={course_module}', '{forum}');
         $rules[] = new restore_log_rule('forum', 'add post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}#p{forum_post}&parent={forum_post}', '{forum_post}');
+        $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'prune post', 'discuss.php?d={forum_discussion}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'delete post', 'discuss.php?d={forum_discussion}', '[post]');
 
index 11d8e78..20f1a31 100644 (file)
@@ -2309,9 +2309,14 @@ abstract class lesson_page extends lesson_base {
         }
         if (count($this->answers)>0) {
             $count = 0;
+            $qtype = $properties->qtype;
             foreach ($this->answers as $answer) {
-                $properties->{'answer_editor['.$count.']'} = array('text'=>$answer->answer, 'format'=>$answer->answerformat);
-                $properties->{'response_editor['.$count.']'} = array('text'=>$answer->response, 'format'=>$answer->responseformat);
+                $properties->{'answer_editor['.$count.']'} = array('text' => $answer->answer, 'format' => $answer->answerformat);
+                if ($qtype != LESSON_PAGE_MATCHING) {
+                    $properties->{'response_editor['.$count.']'} = array('text' => $answer->response, 'format' => $answer->responseformat);
+                } else {
+                    $properties->{'response_editor['.$count.']'} = $answer->response;
+                }
                 $properties->{'jumpto['.$count.']'} = $answer->jumpto;
                 $properties->{'score['.$count.']'} = $answer->score;
                 $count++;
index be4be19..09cdf47 100644 (file)
@@ -72,16 +72,17 @@ class lesson_page_type_matching extends lesson_page {
         foreach ($answers as $answer) {
             // get all the response
             if ($answer->response != NULL) {
-                $responses[] = trim($answer->response);
+                $responses[$answer->id] = trim($answer->response);
             }
         }
 
         $responseoptions = array(''=>get_string('choosedots'));
         if (!empty($responses)) {
-            shuffle($responses);
-            $responses = array_unique($responses);
-            foreach ($responses as $response) {
-                $responseoptions[htmlspecialchars(trim($response))] = $response;
+            $shuffleresponses = $responses;
+            shuffle($shuffleresponses);
+            foreach ($shuffleresponses as  $response) {
+                $key = array_search($response, $responses);
+                $responseoptions[$key] = $response;
             }
         }
         if (isset($USER->modattempts[$this->lesson->id]) && !empty($attempt->useranswer)) {
@@ -115,9 +116,9 @@ class lesson_page_type_matching extends lesson_page {
                 $answer->answer = $properties->answer_editor[$i]['text'];
                 $answer->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $answer->response = $properties->response_editor[$i]['text'];
-                $answer->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $answer->response = $properties->response_editor[$i];
+                $answer->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -171,27 +172,26 @@ class lesson_page_type_matching extends lesson_page {
         $wrong   = array_shift($answers);
 
         foreach ($answers as $key=>$answer) {
-            if ($answer->answer === '' or $answer->response === '') {
-                // incomplete option!
-                unset($answers[$key]);
+            if ($answer->answer !== '' or $answer->response !== '') {
+                $answers[$answer->id] = $answer;
             }
+            unset($answers[$key]);
         }
         // get he users exact responses for record keeping
         $hits = 0;
         $userresponse = array();
-        foreach ($response as $key => $value) {
-            foreach($answers as $answer) {
-                if ($value === $answer->response) {
-                    $userresponse[] = $answer->id;
-                }
-                if ((int)$answer->id === (int)$key) {
-                    $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$value;
-                }
-                if ((int)$answer->id === (int)$key and $value === $answer->response) {
+        foreach ($response as $id => $value) {
+            $userresponse[] = $value;
+            // Make sure the user's answer is exist in question's answer
+            if (array_key_exists($id, $answers)) {
+                $answer = $answers[$id];
+                $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$answers[$value]->response;
+                if ($id == $value) {
                     $hits++;
                 }
             }
         }
+
         $result->userresponse = implode(",", $userresponse);
 
         if ($hits == count($answers)) {
@@ -315,9 +315,9 @@ class lesson_page_type_matching extends lesson_page {
                 $this->answers[$i]->answer = $properties->answer_editor[$i]['text'];
                 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $this->answers[$i]->response = $properties->response_editor[$i]['text'];
-                $this->answers[$i]->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $this->answers[$i]->response = $properties->response_editor[$i];
+                $this->answers[$i]->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -473,12 +473,18 @@ class lesson_add_page_form_matching extends lesson_add_page_form_base {
         for ($i = 2; $i < $this->_customdata['lesson']->maxanswers+2; $i++) {
             $this->_form->addElement('header', 'matchingpair'.($i-1), get_string('matchingpair', 'lesson', $i-1));
             $this->add_answer($i, NULL, ($i < 4));
-            $this->add_response($i, get_string('matchesanswer','lesson'), ($i < 4));
+            $required = ($i < 4);
+            $label = get_string('matchesanswer','lesson');
+            $count = $i;
+            $this->_form->addElement('text', 'response_editor['.$count.']', $label, array('size'=>'50'));
+            $this->_form->setDefault('response_editor['.$count.']', '');
+            if ($required) {
+                $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client');
+            }
         }
     }
 }
 
-
 class lesson_display_answer_form_matching extends moodleform {
 
     public function definition() {
index c8776de..175e5c6 100644 (file)
@@ -100,7 +100,8 @@ class mod_quiz_overdue_attempt_updater {
 
 
         // SQL to compute timeclose and timelimit for each attempt:
-        $quizausersql = quiz_get_attempt_usertime_sql();
+        $quizausersql = quiz_get_attempt_usertime_sql(
+                "iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
 
         // This query should have all the quiz_attempts columns.
         return $DB->get_recordset_sql("
@@ -116,6 +117,6 @@ class mod_quiz_overdue_attempt_updater {
             AND quiza.timecheckstate <= :processto
        ORDER BY quiz.course, quiza.quiz",
 
-                array('processto' => $processto));
+                array('processto' => $processto, 'iprocessto' => $processto));
     }
 }
index ae23dd8..ca78f67 100644 (file)
@@ -783,34 +783,48 @@ function quiz_update_open_attempts(array $conditions) {
     }
 
     $params = array();
-    $coursecond = '';
-    $usercond = '';
-    $quizcond = '';
-    $groupcond = '';
+    $wheres = array("quiza.state IN ('inprogress', 'overdue')");
+    $iwheres = array("iquiza.state IN ('inprogress', 'overdue')");
 
     if (isset($conditions['courseid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'cid');
         $params = array_merge($params, $inparams);
-        $coursecond = "AND quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'icid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
     }
+
     if (isset($conditions['userid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'uid');
         $params = array_merge($params, $inparams);
-        $usercond = "AND quiza.userid $incond";
+        $wheres[] = "quiza.userid $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'iuid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.userid $incond";
     }
+
     if (isset($conditions['quizid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'qid');
         $params = array_merge($params, $inparams);
-        $quizcond = "AND quiza.quiz $incond";
+        $wheres[] = "quiza.quiz $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'iqid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz $incond";
     }
+
     if (isset($conditions['groupid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'gid');
         $params = array_merge($params, $inparams);
-        $groupcond = "AND quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'igid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
     }
 
     // SQL to compute timeclose and timelimit for each attempt:
-    $quizausersql = quiz_get_attempt_usertime_sql();
+    $quizausersql = quiz_get_attempt_usertime_sql(
+            implode("\n                AND ", $iwheres));
 
     // SQL to compute the new timecheckstate
     $timecheckstatesql = "
@@ -822,11 +836,7 @@ function quiz_update_open_attempts(array $conditions) {
           CASE WHEN quiza.state = 'overdue' THEN quiz.graceperiod ELSE 0 END";
 
     // SQL to select which attempts to process
-    $attemptselect = " quiza.state IN ('inprogress', 'overdue')
-                       $coursecond
-                       $usercond
-                       $quizcond
-                       $groupcond";
+    $attemptselect = implode("\n                         AND ", $wheres);
 
    /*
     * Each database handles updates with inner joins differently:
@@ -876,9 +886,14 @@ function quiz_update_open_attempts(array $conditions) {
 /**
  * Returns SQL to compute timeclose and timelimit for every attempt, taking into account user and group overrides.
  *
- * @return string         SQL select with columns attempt.id, usertimeclose, usertimelimit
+ * @param string $redundantwhereclauses extra where clauses to add to the subquery
+ *      for performance. These can use the table alias iquiza for the quiz attempts table.
+ * @return string SQL select with columns attempt.id, usertimeclose, usertimelimit.
  */
-function quiz_get_attempt_usertime_sql() {
+function quiz_get_attempt_usertime_sql($redundantwhereclauses = '') {
+    if ($redundantwhereclauses) {
+        $redundantwhereclauses = 'WHERE ' . $redundantwhereclauses;
+    }
     // The multiple qgo JOINS are necessary because we want timeclose/timelimit = 0 (unlimited) to supercede
     // any other group override
     $quizausersql = "
@@ -894,6 +909,7 @@ function quiz_get_attempt_usertime_sql() {
       LEFT JOIN {quiz_overrides} qgo2 ON qgo2.quiz = iquiza.quiz AND qgo2.groupid = gm.groupid AND qgo2.timeclose > 0
       LEFT JOIN {quiz_overrides} qgo3 ON qgo3.quiz = iquiza.quiz AND qgo3.groupid = gm.groupid AND qgo3.timelimit = 0
       LEFT JOIN {quiz_overrides} qgo4 ON qgo4.quiz = iquiza.quiz AND qgo4.groupid = gm.groupid AND qgo4.timelimit > 0
+          $redundantwhereclauses
        GROUP BY iquiza.id, iquiz.id, iquiz.timeclose, iquiz.timelimit";
     return $quizausersql;
 }
index c2f1c40..182de24 100644 (file)
@@ -745,7 +745,7 @@ function scorm_course_format_display($user, $course) {
 }
 
 function scorm_view_display ($user, $scorm, $action, $cm) {
-    global $CFG, $DB, $PAGE, $OUTPUT;
+    global $CFG, $DB, $PAGE, $OUTPUT, $COURSE;
 
     if ($scorm->scormtype != SCORM_TYPE_LOCAL && $scorm->updatefreq == SCORM_UPDATE_EVERYTIME) {
         scorm_parse($scorm, false);
@@ -824,7 +824,7 @@ function scorm_view_display ($user, $scorm, $action, $cm) {
                       <label for="a"><?php print_string('newattempt', 'scorm') ?></label>
             <?php
         }
-        if (!empty($scorm->popup)) {
+        if ($COURSE->format != 'scorm' && !empty($scorm->popup)) {
             echo '<input type="hidden" name="display" value="popup" />'."\n";
         }
         ?>
index f89d604..b53d09a 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062504.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062504.01;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.4 (Build: 20130114)';  // Human-friendly version name
+$release  = '2.3.4+ (Build: 20130118)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level