Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'master' into install_master

  • Loading branch information...
commit 967bc47c80346cf6280f2a1385fc50df926cde36 2 parents 00db87a + fe41ba7
authored November 19, 2011

Showing 38 changed files with 356 additions and 104 deletions. Show diff stats Hide diff stats

  1. 9  backup/moodle2/restore_stepslib.php
  2. 17  lib/db/upgrade.php
  3. 9  lib/moodlelib.php
  4. 12  lib/questionlib.php
  5. 4  lib/simpletest/testcompletionlib.php
  6. 2  mod/assignment/lib.php
  7. 3  mod/forum/lib.php
  8. 9  mod/quiz/attemptlib.php
  9. 8  mod/quiz/editlib.php
  10. 71  mod/quiz/grade.php
  11. 2  mod/quiz/module.js
  12. 10  mod/quiz/report/attemptsreport.php
  13. 2  mod/quiz/startattempt.php
  14. 9  mod/quiz/styles.css
  15. 2  mod/quiz/summary.php
  16. 2  mod/scorm/lib.php
  17. 4  mod/wiki/styles.css
  18. 4  question/behaviour/adaptive/behaviour.php
  19. 24  question/behaviour/behaviourbase.php
  20. 4  question/behaviour/deferredfeedback/behaviour.php
  21. 4  question/behaviour/immediatefeedback/behaviour.php
  22. 4  question/behaviour/informationitem/behaviour.php
  23. 4  question/behaviour/interactive/behaviour.php
  24. 4  question/behaviour/interactivecountback/behaviour.php
  25. 5  question/behaviour/missing/behaviour.php
  26. 7  question/behaviour/upgrade.txt
  27. 2  question/editlib.php
  28. 63  question/engine/datalib.php
  29. 49  question/renderer.php
  30. 6  question/type/edit_question_form.php
  31. 2  question/type/numerical/edit_numerical_form.php
  32. 7  question/type/numerical/questiontype.php
  33. 69  theme/base/style/core.css
  34. 2  theme/base/style/course.css
  35. 6  theme/mymobile/renderers.php
  36. 2  theme/standard/style/core.css
  37. 4  version.php
  38. 13  webservice/renderer.php
9  backup/moodle2/restore_stepslib.php
@@ -802,7 +802,14 @@ public function process_grouping_group($data) {
802 802
 
803 803
         $data->groupingid = $this->get_new_parentid('grouping'); // Use new parentid
804 804
         $data->groupid    = $this->get_mappingid('group', $data->groupid); // Get from mappings
805  
-        $DB->insert_record('groupings_groups', $data);  // No need to set this mapping (no child info nor files)
  805
+
  806
+        $params = array();
  807
+        $params['groupingid'] = $data->groupingid;
  808
+        $params['groupid']    = $data->groupid;
  809
+
  810
+        if (!$DB->record_exists('groupings_groups', $params)) {
  811
+            $DB->insert_record('groupings_groups', $data);  // No need to set this mapping (no child info nor files)
  812
+        }
806 813
     }
807 814
 
808 815
     protected function after_execute() {
17  lib/db/upgrade.php
@@ -6916,6 +6916,23 @@ function xmldb_main_upgrade($oldversion) {
6916 6916
         upgrade_main_savepoint(true, 2011110200.02);
6917 6917
     }
6918 6918
 
  6919
+    if ($oldversion < 2011111500.01) {
  6920
+        upgrade_set_timeout(60*20); // this may take a while
  6921
+        // Remove duplicate entries from groupings_groups table
  6922
+        $sql = 'SELECT MIN(id) AS firstid, groupingid, groupid FROM {groupings_groups} '.
  6923
+               'GROUP BY groupingid, groupid HAVING COUNT(id)>1';
  6924
+        $badrs = $DB->get_recordset_sql($sql);
  6925
+        foreach ($badrs as $badrec) {
  6926
+            $where = 'groupingid = ? and groupid = ? and id > ?';
  6927
+            $params = array($badrec->groupingid, $badrec->groupid, $badrec->firstid);
  6928
+            $DB->delete_records_select('groupings_groups', $where, $params);
  6929
+        }
  6930
+        $badrs->close();
  6931
+
  6932
+        // Main savepoint reached
  6933
+        upgrade_main_savepoint(true, 2011111500.01);
  6934
+    }
  6935
+
6919 6936
     return true;
6920 6937
 }
6921 6938
 
9  lib/moodlelib.php
@@ -8725,12 +8725,17 @@ function generate_password($maxlen=10) {
8725 8725
         $filler1 = $fillers[rand(0, strlen($fillers) - 1)];
8726 8726
         $password = $word1 . $filler1 . $word2;
8727 8727
     } else {
8728  
-        $maxlen = !empty($CFG->minpasswordlength) ? $CFG->minpasswordlength : 0;
  8728
+        $minlen = !empty($CFG->minpasswordlength) ? $CFG->minpasswordlength : 0;
8729 8729
         $digits = $CFG->minpassworddigits;
8730 8730
         $lower = $CFG->minpasswordlower;
8731 8731
         $upper = $CFG->minpasswordupper;
8732 8732
         $nonalphanum = $CFG->minpasswordnonalphanum;
8733  
-        $additional = $maxlen - ($lower + $upper + $digits + $nonalphanum);
  8733
+        $total = $lower + $upper + $digits + $nonalphanum;
  8734
+        // minlength should be the greater one of the two ( $minlen and $total )
  8735
+        $minlen = $minlen < $total ? $total : $minlen;
  8736
+        // maxlen can never be smaller than minlen
  8737
+        $maxlen = $minlen > $maxlen ? $minlen : $maxlen;
  8738
+        $additional = $maxlen - $total;
8734 8739
 
8735 8740
         // Make sure we have enough characters to fulfill
8736 8741
         // complexity requirements
12  lib/questionlib.php
@@ -825,16 +825,8 @@ function get_question_options(&$questions, $loadtags = false) {
825 825
  * @return string the HTML for the img tag.
826 826
  */
827 827
 function print_question_icon($question) {
828  
-    global $OUTPUT;
829  
-
830  
-    $qtype = question_bank::get_qtype($question->qtype, false);
831  
-    $namestr = $qtype->menu_name();
832  
-
833  
-    // TODO convert to return a moodle_icon object, or whatever the class is.
834  
-    $html = '<img src="' . $OUTPUT->pix_url('icon', $qtype->plugin_name()) . '" alt="' .
835  
-            $namestr . '" title="' . $namestr . '" />';
836  
-
837  
-    return $html;
  828
+    global $PAGE;
  829
+    return $PAGE->get_renderer('question', 'bank')->qtype_icon($question->qtype);
838 830
 }
839 831
 
840 832
 /**
4  lib/simpletest/testcompletionlib.php
@@ -527,7 +527,7 @@ function test_get_progress_all() {
527 527
         $c->__construct((object)array('id'=>42));
528 528
 
529 529
         // 1) Basic usage
530  
-        $c->expectAt(0,'get_tracked_users',array(false, array(), 0, '', '', ''));
  530
+        $c->expectAt(0,'get_tracked_users',array(false, array(), 0, '', '', '', null));
531 531
         $c->setReturnValueAt(0,'get_tracked_users',array(
532 532
             (object)array('id'=>100,'firstname'=>'Woot','lastname'=>'Plugh'),
533 533
             (object)array('id'=>201,'firstname'=>'Vroom','lastname'=>'Xyzzy'),
@@ -556,7 +556,7 @@ function test_get_progress_all() {
556 556
             ),$c->get_progress_all(false));
557 557
 
558 558
         // 2) With more than 1,000 results
559  
-        $c->expectAt(1,'get_tracked_users',array(true, 3, 0, '', '', ''));
  559
+        $c->expectAt(1,'get_tracked_users',array(true, 3, 0, '', '', '', null));
560 560
 
561 561
         $tracked=array();
562 562
         $ids=array();
2  mod/assignment/lib.php
@@ -3540,7 +3540,7 @@ function assignment_get_coursemodule_info($coursemodule) {
3540 3540
         }
3541 3541
         if ($coursemodule->showdescription) {
3542 3542
             // Convert intro to html. Do not filter cached version, filters run at display time.
3543  
-            $info->content = format_module_intro('assignment', $assignment, $coursemodule->id, false);
  3543
+            $result->content = format_module_intro('assignment', $assignment, $coursemodule->id, false);
3544 3544
         }
3545 3545
         return $result;
3546 3546
     } else {
3  mod/forum/lib.php
@@ -5943,8 +5943,9 @@ function forum_tp_mark_posts_read($user, $postids) {
5943 5943
 
5944 5944
     if ($new) {
5945 5945
         list($usql, $new_params) = $DB->get_in_or_equal($new);
5946  
-        $params = array($user->id, $now, $now, $user->id, $cutoffdate);
  5946
+        $params = array($user->id, $now, $now, $user->id);
5947 5947
         $params = array_merge($params, $new_params);
  5948
+        $params[] = $cutoffdate;
5948 5949
 
5949 5950
         $sql = "INSERT INTO {forum_read} (userid, postid, discussionid, forumid, firstread, lastread)
5950 5951
 
9  mod/quiz/attemptlib.php
@@ -418,10 +418,17 @@ class quiz_attempt {
418 418
      * @param object $quiz the quiz object for this attempt and user.
419 419
      * @param object $cm the course_module object for this quiz.
420 420
      * @param object $course the row from the course table for the course we belong to.
  421
+     * @param bool $loadquestions (optional) if true, the default, load all the details
  422
+     *      of the state of each question. Else just set up the basic details of the attempt.
421 423
      */
422  
-    public function __construct($attempt, $quiz, $cm, $course) {
  424
+    public function __construct($attempt, $quiz, $cm, $course, $loadquestions = true) {
423 425
         $this->attempt = $attempt;
424 426
         $this->quizobj = new quiz($quiz, $cm, $course);
  427
+
  428
+        if (!$loadquestions) {
  429
+            return;
  430
+        }
  431
+
425 432
         $this->quba = question_engine::load_questions_usage_by_activity($this->attempt->uniqueid);
426 433
         $this->determine_layout();
427 434
         $this->number_questions();
8  mod/quiz/editlib.php
@@ -781,7 +781,7 @@ function quiz_print_singlequestion($question, $returnurl, $quiz) {
781 781
     echo quiz_question_edit_button($quiz->cmid, $question, $returnurl,
782 782
             quiz_question_tostring($question) . ' ');
783 783
     echo '<span class="questiontype">';
784  
-    print_question_icon($question);
  784
+    echo print_question_icon($question);
785 785
     echo ' ' . question_bank::get_qtype_name($question->qtype) . '</span>';
786 786
     echo '<span class="questionpreview">' .
787 787
             quiz_question_preview_button($quiz, $question, true) . '</span>';
@@ -807,7 +807,7 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
807 807
     }
808 808
 
809 809
     echo '<div class="randomquestionfromcategory">';
810  
-    print_question_icon($question);
  810
+    echo print_question_icon($question);
811 811
     print_random_option_icon($question);
812 812
     echo ' ' . get_string('randomfromcategory', 'quiz') . '</div>';
813 813
 
@@ -886,7 +886,7 @@ function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktoo
886 886
 function quiz_print_singlequestion_reordertool($question, $returnurl, $quiz) {
887 887
     echo '<div class="singlequestion">';
888 888
     echo '<label for="s' . $question->id . '">';
889  
-    print_question_icon($question);
  889
+    echo print_question_icon($question);
890 890
     echo ' ' . quiz_question_tostring($question);
891 891
     echo '</label>';
892 892
     echo '<span class="questionpreview">' .
@@ -920,7 +920,7 @@ function quiz_print_randomquestion_reordertool(&$question, &$pageurl, &$quiz) {
920 920
     echo '<div class="quiz_randomquestion">';
921 921
     echo '<div class="randomquestionfromcategory">';
922 922
     echo $reordercheckboxlabel;
923  
-    print_question_icon($question);
  923
+    echo print_question_icon($question);
924 924
     print_random_option_icon($question);
925 925
 
926 926
     if ($questioncount == 0) {
71  mod/quiz/grade.php
@@ -26,27 +26,68 @@
26 26
 
27 27
 
28 28
 require_once(dirname(__FILE__) . '/../../config.php');
  29
+require_once($CFG->dirroot . '/mod/quiz/locallib.php');
29 30
 require_once($CFG->dirroot . '/mod/quiz/report/reportlib.php');
30 31
 
31 32
 
32 33
 $id = required_param('id', PARAM_INT);
  34
+$userid = optional_param('userid', 0, PARAM_INT);
33 35
 
34  
-if (!$cm = get_coursemodule_from_id('quiz', $id)) {
35  
-    print_error('invalidcoursemodule');
36  
-}
37  
-if (!$quiz = $DB->get_record('quiz', array('id' => $cm->instance))) {
38  
-    print_error('invalidquizid');
39  
-}
40  
-if (!$course = $DB->get_record('course', array('id' => $quiz->course))) {
41  
-    print_error('coursemisconf');
  36
+$cm = get_coursemodule_from_id('quiz', $id, 0, false, MUST_EXIST);
  37
+$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
  38
+$quiz = $DB->get_record('quiz', array('id' => $cm->instance), '*', MUST_EXIST);
  39
+require_login($course, false, $cm);
  40
+
  41
+$reportlist = quiz_report_list(context_module::instance($cm->id));
  42
+if (empty($reportlist) || $userid == $USER->id) {
  43
+    // If the user cannot see reports, or can see reports but is looking
  44
+    // at their own grades, redirect them to the view.php page.
  45
+    // (The looking at their own grades case is unlikely, since users who
  46
+    // appear in the gradebook are unlikely to be able to see quiz reports,
  47
+    // but it is possible.)
  48
+    redirect(new moodle_url('/mod/quiz/view.php', array('id' => $cm->id)));
42 49
 }
43 50
 
44  
-require_login($course, false, $cm);
  51
+// Now we know the user is interested in reports. If they are interested in a
  52
+// specific other user, try to send them to the most appropriate attempt review page.
  53
+if ($userid) {
45 54
 
46  
-$reportlist = quiz_report_list(get_context_instance(CONTEXT_MODULE, $cm->id));
47  
-if (!empty($reportlist)) {
48  
-    redirect(new moodle_url('/mod/quiz/report.php', array(
49  
-            'id' => $cm->id, 'mode' => reset($reportlist))));
50  
-} else {
51  
-    redirect(new moodle_url('/mod/quiz/view.php', array('id' =>  $cm->id)));
  55
+    // Work out which attempt is most significant from a grading point of view.
  56
+    $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished');
  57
+    $attempt = null;
  58
+    switch ($quiz->grademethod) {
  59
+        case QUIZ_ATTEMPTFIRST:
  60
+            $attempt = reset($attempts);
  61
+            break;
  62
+
  63
+        case QUIZ_ATTEMPTLAST:
  64
+        case QUIZ_GRADEAVERAGE:
  65
+            $attempt = end($attempts);
  66
+            break;
  67
+
  68
+        case QUIZ_GRADEHIGHEST:
  69
+            $maxmark = 0;
  70
+            foreach ($attempts as $at) {
  71
+                // >=, since we want to most recent relevant attempt.
  72
+                if ((float) $at->sumgrades >= $maxmark) {
  73
+                    $maxmark = $at->sumgrades;
  74
+                    $attempt = $at;
  75
+                }
  76
+            }
  77
+            break;
  78
+    }
  79
+
  80
+    // If the user can review the relevant attempt, redirect to it.
  81
+    if ($attempt) {
  82
+        $attemptobj = new quiz_attempt($attempt, $quiz, $cm, $course, false);
  83
+        if ($attemptobj->is_review_allowed()) {
  84
+            redirect($attemptobj->review_url());
  85
+        }
  86
+    }
  87
+
  88
+    // Otherwise, fall thorugh to the generic case.
52 89
 }
  90
+
  91
+// Send the user to the first report they can see.
  92
+redirect(new moodle_url('/mod/quiz/report.php', array(
  93
+        'id' => $cm->id, 'mode' => reset($reportlist))));
2  mod/quiz/module.js
@@ -170,7 +170,7 @@ M.mod_quiz.nav.init = function(Y) {
170 170
 
171 171
     if (Y.one('a.endtestlink')) {
172 172
         Y.on('click', function(e) {
173  
-            e.preventDefault(e);
  173
+            e.preventDefault();
174 174
             Y.one('#followingpage').set('value', -1);
175 175
             Y.one('#responseform').submit();
176 176
         }, 'a.endtestlink');
10  mod/quiz/report/attemptsreport.php
@@ -621,13 +621,21 @@ protected function add_latest_state_join($slot) {
621 621
             return;
622 622
         }
623 623
 
  624
+        // This condition roughly filters the list of attempts to be considered.
  625
+        // It is only used in a subselect to help crappy databases (see MDL-30122)
  626
+        // therefore, it is better to use a very simple join, which may include
  627
+        // too many records, than to do a super-accurate join.
  628
+        $qubaids = new qubaid_join("{quiz_attempts} {$alias}quiza", "{$alias}quiza.uniqueid",
  629
+                "{$alias}quiza.quiz = :{$alias}quizid", array("{$alias}quizid" => $this->sql->params['quizid']));
  630
+
624 631
         $dm = new question_engine_data_mapper();
625  
-        $inlineview = $dm->question_attempt_latest_state_view($alias);
  632
+        list($inlineview, $viewparams) = $dm->question_attempt_latest_state_view($alias, $qubaids);
626 633
 
627 634
         $this->sql->fields .= ",\n$fields";
628 635
         $this->sql->from .= "\nLEFT JOIN $inlineview ON " .
629 636
                 "$alias.questionusageid = quiza.uniqueid AND $alias.slot = :{$alias}slot";
630 637
         $this->sql->params[$alias . 'slot'] = $slot;
  638
+        $this->sql->params = array_merge($this->sql->params, $viewparams);
631 639
     }
632 640
 
633 641
     /**
2  mod/quiz/startattempt.php
@@ -101,7 +101,7 @@
101 101
 $output = $PAGE->get_renderer('mod_quiz');
102 102
 if (!$quizobj->is_preview_user() && $messages) {
103 103
     print_error('attempterror', 'quiz', $quizobj->view_url(),
104  
-            $output->print_messages($messages));
  104
+            $output->access_messages($messages));
105 105
 }
106 106
 
107 107
 if ($accessmanager->is_preflight_check_required($currentattemptid)) {
9  mod/quiz/styles.css
@@ -96,6 +96,13 @@ div.editq div.question div.content .singlequestion a .questiontext{text-decorati
96 96
 #page-mod-quiz-mod #reviewoptionshdr fieldset.fgroup span label,
97 97
 #adminquizreviewoptions span label {margin-left: 0.4em;}
98 98
 
  99
+#page-mod-quiz-mod.dir-rtl #reviewoptionshdr .fitem,
  100
+#adminquizreviewoptions .group {float: right; width: 24%;}
  101
+#page-mod-quiz-mod.dir-rtl #reviewoptionshdr fieldset.fgroup span,
  102
+#adminquizreviewoptions span {float: right; clear: right;}
  103
+#page-mod-quiz-mod.dir-rtl #reviewoptionshdr .fitemtitle,
  104
+#adminquizreviewoptions .fitemtitle {text-align: right;}
  105
+
99 106
 /** Mod quiz view **/
100 107
 #page-mod-quiz-view .quizinfo,
101 108
 #page-mod-quiz-view #page .quizgradefeedback,
@@ -377,4 +384,4 @@ bank window's title is prominent enough*/
377 384
 .qnum label {padding-right: 0.25em;}
378 385
 
379 386
 /** settings.php */
380  
-#adminquizreviewoptions {margin-bottom: 0.5em;}
  387
+#adminquizreviewoptions {margin-bottom: 0.5em;}
2  mod/quiz/summary.php
@@ -61,7 +61,7 @@
61 61
 $output = $PAGE->get_renderer('mod_quiz');
62 62
 if (!$attemptobj->is_preview_user() && $messages) {
63 63
     print_error('attempterror', 'quiz', $attemptobj->view_url(),
64  
-            $output->print_messages($messages));
  64
+            $output->access_messages($messages));
65 65
 }
66 66
 if ($accessmanager->is_preflight_check_required($attemptobj->get_attemptid())) {
67 67
     redirect($attemptobj->start_attempt_url(null, $page));
2  mod/scorm/lib.php
@@ -510,7 +510,7 @@ function scorm_cron () {
510 510
         $cfg_scorm = get_config('scorm');
511 511
         if (!empty($cfg_scorm->allowaicchacp)) {
512 512
             $expiretime = time() - ($cfg_scorm->aicchacpkeepsessiondata*24*60*60);
513  
-            $DB->delete_records_select('scorm_aicc_session', 'WHERE timemodified < ?', array($expiretime));
  513
+            $DB->delete_records_select('scorm_aicc_session', 'timemodified < ?', array($expiretime));
514 514
         }
515 515
     }
516 516
 
4  mod/wiki/styles.css
@@ -171,6 +171,10 @@
171 171
     float: right;
172 172
 }
173 173
 
  174
+.dir-rtl .wiki_diffuserleft {
  175
+    float: left;
  176
+}
  177
+
174 178
 .wiki_diffuserright {
175 179
     float: left;
176 180
 }
4  question/behaviour/adaptive/behaviour.php
@@ -38,8 +38,8 @@
38 38
 class qbehaviour_adaptive extends question_behaviour_with_save {
39 39
     const IS_ARCHETYPAL = true;
40 40
 
41  
-    public function required_question_definition_type() {
42  
-        return 'question_automatically_gradable';
  41
+    public function is_compatible_question(question_definition $question) {
  42
+        return $question instanceof question_automatically_gradable;
43 43
     }
44 44
 
45 45
     public function get_expected_data() {
24  question/behaviour/behaviourbase.php
@@ -70,21 +70,39 @@
70 70
     public function __construct(question_attempt $qa, $preferredbehaviour) {
71 71
         $this->qa = $qa;
72 72
         $this->question = $qa->get_question();
73  
-        $requiredclass = $this->required_question_definition_type();
74  
-        if (!$this->question instanceof $requiredclass) {
  73
+        if (!$this->is_compatible_question($this->question)) {
75 74
             throw new coding_exception('This behaviour (' . $this->get_name() .
76 75
                     ') cannot work with this question (' . get_class($this->question) . ')');
77 76
         }
78 77
     }
79 78
 
80 79
     /**
  80
+     * Some behaviours can only work with certing types of question. This method
  81
+     * allows the behaviour to verify that a question is compatible.
  82
+     *
  83
+     * This implementation is only provided for backwards-compatibility. You should
  84
+     * override this method if you are implementing a behaviour.
  85
+     *
  86
+     * @param question_definition $question the question.
  87
+     */
  88
+    public function is_compatible_question(question_definition $question) {
  89
+        $requiredclass = $this->required_question_definition_type();
  90
+        return $this->question instanceof $requiredclass;
  91
+    }
  92
+
  93
+    /**
81 94
      * Most behaviours can only work with {@link question_definition}s
82 95
      * of a particular subtype, or that implement a particular interface.
83 96
      * This method lets the behaviour document that. The type of
84 97
      * question passed to the constructor is then checked against this type.
  98
+     *
  99
+     * @deprecated since 2.2. Please use/override {@link is_compatible_question()} instead.
  100
+     *
85 101
      * @return string class/interface name.
86 102
      */
87  
-    public abstract function required_question_definition_type();
  103
+    protected function required_question_definition_type() {
  104
+        return 'question_definition';
  105
+    }
88 106
 
89 107
     /**
90 108
      * @return string the name of this behaviour. For example the name of
4  question/behaviour/deferredfeedback/behaviour.php
@@ -40,8 +40,8 @@
40 40
 class qbehaviour_deferredfeedback extends question_behaviour_with_save {
41 41
     const IS_ARCHETYPAL = true;
42 42
 
43  
-    public function required_question_definition_type() {
44  
-        return 'question_automatically_gradable';
  43
+    public function is_compatible_question(question_definition $question) {
  44
+        return $question instanceof question_automatically_gradable;
45 45
     }
46 46
 
47 47
     public static function get_unused_display_options() {
4  question/behaviour/immediatefeedback/behaviour.php
@@ -42,8 +42,8 @@
42 42
 class qbehaviour_immediatefeedback extends question_behaviour_with_save {
43 43
     const IS_ARCHETYPAL = true;
44 44
 
45  
-    public function required_question_definition_type() {
46  
-        return 'question_automatically_gradable';
  45
+    public function is_compatible_question(question_definition $question) {
  46
+        return $question instanceof question_automatically_gradable;
47 47
     }
48 48
 
49 49
     public function get_min_fraction() {
4  question/behaviour/informationitem/behaviour.php
@@ -39,8 +39,8 @@
39 39
  */
40 40
 class qbehaviour_informationitem extends question_behaviour {
41 41
 
42  
-    public function required_question_definition_type() {
43  
-        return 'question_definition';
  42
+    public function is_compatible_question(question_definition $question) {
  43
+        return true;
44 44
     }
45 45
 
46 46
     public function get_expected_data() {
4  question/behaviour/interactive/behaviour.php
@@ -52,8 +52,8 @@ class qbehaviour_interactive extends question_behaviour_with_save {
52 52
      */
53 53
     const READONLY_EXCEPT_TRY_AGAIN = 23485299;
54 54
 
55  
-    public function required_question_definition_type() {
56  
-        return 'question_automatically_gradable';
  55
+    public function is_compatible_question(question_definition $question) {
  56
+        return $question instanceof question_automatically_gradable;
57 57
     }
58 58
 
59 59
     public function get_right_answer_summary() {
4  question/behaviour/interactivecountback/behaviour.php
@@ -64,8 +64,8 @@
64 64
 class qbehaviour_interactivecountback extends qbehaviour_interactive {
65 65
     const IS_ARCHETYPAL = false;
66 66
 
67  
-    public function required_question_definition_type() {
68  
-        return 'question_automatically_gradable_with_countback';
  67
+    public function is_compatible_question(question_definition $question) {
  68
+        return $question instanceof question_automatically_gradable_with_countback;
69 69
     }
70 70
 
71 71
     protected function adjust_fraction($fraction, question_attempt_pending_step $pendingstep) {
5  question/behaviour/missing/behaviour.php
@@ -45,8 +45,9 @@
45 45
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 46
  */
47 47
 class qbehaviour_missing extends question_behaviour {
48  
-    public function required_question_definition_type() {
49  
-        return 'question_definition';
  48
+
  49
+    public function is_compatible_question(question_definition $question) {
  50
+        return true;
50 51
     }
51 52
 
52 53
     public function summarise_action(question_attempt_step $step) {
7  question/behaviour/upgrade.txt
@@ -2,10 +2,15 @@ This files describes API changes for question behaviour plugins.
2 2
 
3 3
 === 2.2 ===
4 4
 
5  
-* The old
  5
+1) The old
6 6
     public static function get_required_behaviours()
7 7
 method is no more. Instead use the ->dependencies facility in version.php. E.g.
8 8
 $plugin->dependencies = array(
9 9
     'qbehaviour_immediatefeedback' => 2011102700,
10 10
     'qbehaviour_deferredcbm'       => 2011102700
11 11
 );
  12
+
  13
+2) The old required_question_definition_type method has been replaced by a new
  14
+is_compatible_question method. You should change your behaviour to override the
  15
+new method, not the old one. This change has been implemented in a
  16
+backwards-compatible way, so behaviours will not break.
2  question/editlib.php
@@ -1793,7 +1793,7 @@ function print_qtype_to_add_option($qtype) {
1793 1793
     echo '<span class="qtypename">';
1794 1794
     $fakequestion = new stdClass();
1795 1795
     $fakequestion->qtype = $qtype->name();
1796  
-    print_question_icon($fakequestion);
  1796
+    echo print_question_icon($fakequestion);
1797 1797
     echo $qtype->menu_name() . '</span><span class="qtypesummary">' . $summary;
1798 1798
     echo "</span></label>\n";
1799 1799
     echo "</div>\n";
63  question/engine/datalib.php
@@ -865,33 +865,42 @@ public function sum_usage_marks_subquery($qubaid) {
865 865
             END) = 0";
866 866
     }
867 867
 
868  
-    public function question_attempt_latest_state_view($alias) {
869  
-        return "(
870  
-                SELECT
871  
-                    {$alias}qa.id AS questionattemptid,
872  
-                    {$alias}qa.questionusageid,
873  
-                    {$alias}qa.slot,
874  
-                    {$alias}qa.behaviour,
875  
-                    {$alias}qa.questionid,
876  
-                    {$alias}qa.variant,
877  
-                    {$alias}qa.maxmark,
878  
-                    {$alias}qa.minfraction,
879  
-                    {$alias}qa.flagged,
880  
-                    {$alias}qa.questionsummary,
881  
-                    {$alias}qa.rightanswer,
882  
-                    {$alias}qa.responsesummary,
883  
-                    {$alias}qa.timemodified,
884  
-                    {$alias}qas.id AS attemptstepid,
885  
-                    {$alias}qas.sequencenumber,
886  
-                    {$alias}qas.state,
887  
-                    {$alias}qas.fraction,
888  
-                    {$alias}qas.timecreated,
889  
-                    {$alias}qas.userid
890  
-
891  
-                FROM {question_attempts} {$alias}qa
892  
-                JOIN {question_attempt_steps} {$alias}qas ON
893  
-                        {$alias}qas.id = {$this->latest_step_for_qa_subquery($alias . 'qa.id')}
894  
-            ) $alias";
  868
+    /**
  869
+     * Get a subquery that returns the latest step of every qa in some qubas.
  870
+     * Currently, this is only used by the quiz reports. See
  871
+     * {@link quiz_attempt_report_table::add_latest_state_join()}.
  872
+     * @param string $alias alias to use for this inline-view.
  873
+     * @param qubaid_condition $qubaids restriction on which question_usages we
  874
+     *      are interested in. This is important for performance.
  875
+     * @return array with two elements, the SQL fragment and any params requried.
  876
+     */
  877
+    public function question_attempt_latest_state_view($alias, qubaid_condition $qubaids) {
  878
+        return array("(
  879
+                SELECT {$alias}qa.id AS questionattemptid,
  880
+                       {$alias}qa.questionusageid,
  881
+                       {$alias}qa.slot,
  882
+                       {$alias}qa.behaviour,
  883
+                       {$alias}qa.questionid,
  884
+                       {$alias}qa.variant,
  885
+                       {$alias}qa.maxmark,
  886
+                       {$alias}qa.minfraction,
  887
+                       {$alias}qa.flagged,
  888
+                       {$alias}qa.questionsummary,
  889
+                       {$alias}qa.rightanswer,
  890
+                       {$alias}qa.responsesummary,
  891
+                       {$alias}qa.timemodified,
  892
+                       {$alias}qas.id AS attemptstepid,
  893
+                       {$alias}qas.sequencenumber,
  894
+                       {$alias}qas.state,
  895
+                       {$alias}qas.fraction,
  896
+                       {$alias}qas.timecreated,
  897
+                       {$alias}qas.userid
  898
+
  899
+                  FROM {$qubaids->from_question_attempts($alias . 'qa')}
  900
+                  JOIN {question_attempt_steps} {$alias}qas ON
  901
+                           {$alias}qas.id = {$this->latest_step_for_qa_subquery($alias . 'qa.id')}
  902
+                 WHERE {$qubaids->where()}
  903
+            ) $alias", $qubaids->from_where_params());
895 904
     }
896 905
 
897 906
     protected function latest_step_for_qa_subquery($questionattemptid = 'qa.id') {
49  question/renderer.php
... ...
@@ -0,0 +1,49 @@
  1
+<?php
  2
+// This file is part of Moodle - http://moodle.org/
  3
+//
  4
+// Moodle is free software: you can redistribute it and/or modify
  5
+// it under the terms of the GNU General Public License as published by
  6
+// the Free Software Foundation, either version 3 of the License, or
  7
+// (at your option) any later version.
  8
+//
  9
+// Moodle is distributed in the hope that it will be useful,
  10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+// GNU General Public License for more details.
  13
+//
  14
+// You should have received a copy of the GNU General Public License
  15
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
+
  17
+/**
  18
+ * Renderers for outputting parts of the question bank.
  19
+ *
  20
+ * @package    moodlecore
  21
+ * @subpackage questionbank
  22
+ * @copyright  2011 The Open University
  23
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24
+ */
  25
+
  26
+
  27
+defined('MOODLE_INTERNAL') || die();
  28
+
  29
+
  30
+/**
  31
+ * This renderer outputs parts of the question bank.
  32
+ *
  33
+ * @copyright  2011 The Open University
  34
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35
+ */
  36
+class core_question_bank_renderer extends plugin_renderer_base {
  37
+
  38
+    /**
  39
+     * Output the icon for a question type
  40
+     * @param string $qtype the question type.
  41
+     * @return string HTML fragment.
  42
+     */
  43
+    public function qtype_icon($qtype) {
  44
+        $qtype = question_bank::get_qtype($qtype, false);
  45
+        $namestr = $qtype->local_name();
  46
+
  47
+        return $this->pix_icon('icon', $namestr, $qtype->plugin_name(), array('title' => $namestr));
  48
+    }
  49
+}
6  question/type/edit_question_form.php
@@ -344,7 +344,7 @@ protected function add_combined_feedback_fields($withshownumpartscorrect = false
344 344
             $mform->setType($feedbackname, PARAM_RAW);
345 345
 
346 346
             if ($withshownumpartscorrect && $feedbackname == 'partiallycorrectfeedback') {
347  
-                $mform->addElement('checkbox', 'shownumcorrect',
  347
+                $mform->addElement('advcheckbox', 'shownumcorrect',
348 348
                         get_string('options', 'question'),
349 349
                         get_string('shownumpartscorrect', 'question'));
350 350
             }
@@ -361,11 +361,11 @@ protected function get_hint_fields($withclearwrong = false, $withshownumpartscor
361 361
         $repeatedoptions['hint']['type'] = PARAM_RAW;
362 362
 
363 363
         if ($withclearwrong) {
364  
-            $repeated[] = $mform->createElement('checkbox', 'hintclearwrong',
  364
+            $repeated[] = $mform->createElement('advcheckbox', 'hintclearwrong',
365 365
                     get_string('options', 'question'), get_string('clearwrongparts', 'question'));
366 366
         }
367 367
         if ($withshownumpartscorrect) {
368  
-            $repeated[] = $mform->createElement('checkbox', 'hintshownumcorrect', '',
  368
+            $repeated[] = $mform->createElement('advcheckbox', 'hintshownumcorrect', '',
369 369
                     get_string('shownumpartscorrect', 'question'));
370 370
         }
371 371
 
2  question/type/numerical/edit_numerical_form.php
@@ -264,7 +264,7 @@ protected function validate_answers($data, $errors) {
264 264
                 if ($data['fraction'][$key] == 1) {
265 265
                     $maxgrade = true;
266 266
                 }
267  
-                if (!is_numeric($data['tolerance'][$key])) {
  267
+                if ($answer !== '*' && !is_numeric($data['tolerance'][$key])) {
268 268
                     $errors['tolerance['.$key.']'] =
269 269
                             get_string('mustbenumeric', 'qtype_calculated');
270 270
                 }
7  question/type/numerical/questiontype.php
@@ -641,16 +641,17 @@ public function apply_units($response, $separateunit = null) {
641 641
 
642 642
         $numberstring = $matches[0];
643 643
         if ($this->unitsbefore) {
644  
-            $unit = substr($response, 0, -strlen($numberstring));
  644
+            // substr returns false when it means '', so cast back to string.
  645
+            $unit = (string) substr($response, 0, -strlen($numberstring));
645 646
         } else {
646  
-            $unit = substr($response, strlen($numberstring));
  647
+            $unit = (string) substr($response, strlen($numberstring));
647 648
         }
648 649
 
649 650
         if (!is_null($separateunit)) {
650 651
             $unit = $separateunit;
651 652
         }
652 653
 
653  
-        if ($unit && $this->is_known_unit($unit)) {
  654
+        if ($this->is_known_unit($unit)) {
654 655
             $multiplier = 1 / $this->units[$unit];
655 656
         } else {
656 657
             $multiplier = null;
69  theme/base/style/core.css
@@ -218,6 +218,8 @@ a.skip:active {position: static;display: block;}
218 218
 .mform .ftags label.accesshide {display: block;position: static;}
219 219
 .mform .ftags select {margin-bottom: 0.7em;min-width: 22em;}
220 220
 
  221
+input#id_externalurl {direction:ltr;}
  222
+
221 223
 /** Browser corrections for mforms **/
222 224
 .ie .mform .fitem .felement {margin-left:0;text-align:left;float:left;}
223 225
 /** Fix IE double margin + float bugs **/
@@ -720,6 +722,23 @@ body.tag .managelink {padding: 5px;}
720 722
 .mod-indent-15,
721 723
 .mod-indent-huge {margin-left:300px;}
722 724
 
  725
+.dir-rtl .mod-indent-1 {margin-right:20px;margin-left:0;}
  726
+.dir-rtl .mod-indent-2 {margin-right:40px;margin-left:0;}
  727
+.dir-rtl .mod-indent-3 {margin-right:60px;margin-left:0;}
  728
+.dir-rtl .mod-indent-4 {margin-right:80px;margin-left:0;}
  729
+.dir-rtl .mod-indent-5 {margin-right:100px;margin-left:0;}
  730
+.dir-rtl .mod-indent-6 {margin-right:120px;margin-left:0;}
  731
+.dir-rtl .mod-indent-7 {margin-right:140px;margin-left:0;}
  732
+.dir-rtl .mod-indent-8 {margin-right:160px;margin-left:0;}
  733
+.dir-rtl .mod-indent-9 {margin-right:180px;margin-left:0;}
  734
+.dir-rtl .mod-indent-10 {margin-right:200px;margin-left:0;}
  735
+.dir-rtl .mod-indent-11 {margin-right:220px;margin-left:0;}
  736
+.dir-rtl .mod-indent-12 {margin-right:240px;margin-left:0;}
  737
+.dir-rtl .mod-indent-13 {margin-right:260px;margin-left:0;}
  738
+.dir-rtl .mod-indent-14 {margin-right:280px;margin-left:0;}
  739
+.dir-rtl .mod-indent-15,
  740
+.dir-rtl .mod-indent-huge {margin-right:300px;margin-left:0;}
  741
+
723 742
 .dir-rtl .felement.feditor select {margin-right:18.75%;}
724 743
 
725 744
 /* Resourcelib mp3 player size: only width could be changed here, height hardcoded in JS */
@@ -804,3 +823,53 @@ ul li,
804 823
 ol li,
805 824
 .course-content ul.weeks .content .summary ol li,
806 825
 .course-content ul.topics .content .summary ol li {list-style: decimal outside none;}
  826
+
  827
+.dir-rtl #adminsettings #id_s__pathtodu,
  828
+.dir-rtl #adminsettings #id_s__aspellpath,
  829
+.dir-rtl #adminsettings #id_s__pathtodot,
  830
+.dir-rtl #adminsettings #id_s__supportemail,
  831
+.dir-rtl #adminsettings #id_s__supportpage,
  832
+.dir-rtl #adminsettings #id_s__sessioncookie,
  833
+.dir-rtl #adminsettings #id_s__sessioncookiepath,
  834
+.dir-rtl #adminsettings #id_s__sessioncookiedomain,
  835
+.dir-rtl #adminsettings #id_s__proxyhost,
  836
+.dir-rtl #adminsettings #id_s__proxyuser,
  837
+.dir-rtl #adminsettings #id_s__proxypassword,
  838
+.dir-rtl #adminsettings #id_s__proxybypass,
  839
+.dir-rtl #adminsettings #id_s__jabberhost,
  840
+.dir-rtl #adminsettings #id_s__jabberserver,
  841
+.dir-rtl #adminsettings #id_s__jabberusername,
  842
+.dir-rtl #adminsettings #id_s__jabberpassword,
  843
+.dir-rtl #adminsettings #id_s__additionalhtmlhead,
  844
+.dir-rtl #adminsettings #id_s__additionalhtmltopofbody,
  845
+.dir-rtl #adminsettings #id_s__additionalhtmlfooter,
  846
+.dir-rtl #adminsettings #id_s__docroot,
  847
+.dir-rtl #adminsettings #id_s__filter_tex_latexpreamble,
  848
+.dir-rtl #adminsettings #id_s__filter_tex_latexbackground,
  849
+.dir-rtl #adminsettings #id_s__filter_tex_pathlatex,
  850
+.dir-rtl #adminsettings #id_s__filter_tex_pathdvips,
  851
+.dir-rtl #adminsettings #id_s__filter_tex_pathconvert,
  852
+.dir-rtl #adminsettings #id_s__blockedip,
  853
+.dir-rtl #adminsettings #id_s__pathtoclam,
  854
+.dir-rtl #adminsettings #id_s__quarantinedir,
  855
+.dir-rtl #adminsettings #id_s__sitepolicy,
  856
+.dir-rtl #adminsettings #id_s__sitepolicyguest,
  857
+.dir-rtl #adminsettings #id_s__cronremotepassword,
  858
+.dir-rtl #adminsettings #id_s__allowedip,
  859
+.dir-rtl #adminsettings #id_s__blockedip,
  860
+.dir-rtl #adminsettings #id_s_enrol_meta_nosyncroleids,
  861
+.dir-rtl #adminsettings #id_s_enrol_ldap_host_url,
  862
+.dir-rtl #adminsettings #id_s_enrol_ldap_ldapencoding,
  863
+.dir-rtl #adminsettings #id_s_enrol_ldap_bind_dn,
  864
+.dir-rtl #adminsettings #id_s_enrol_ldap_bind_pw,
  865
+.dir-rtl #adminsettings #admin-emoticons .form-text,
  866
+.dir-rtl #adminsettings #admin-role_mapping input[type=text],
  867
+.dir-rtl #adminsettings #id_s_enrol_paypal_paypalbusiness,
  868
+.dir-rtl #adminsettings #id_s_enrol_flatfile_location,
  869
+#page-admin-setting-enrolsettingsflatfile.dir-rtl input[type=text],
  870
+#page-admin-setting-enrolsettingsdatabase.dir-rtl input[type=text],
  871
+#page-admin-auth-db.dir-rtl input[type=text] {direction: ltr;}
  872
+
  873
+#page-admin-setting-enrolsettingsflatfile.dir-rtl .informationbox {direction: ltr;text-align: left;}
  874
+
  875
+#page-admin-grade-edit-scale-edit.dir-rtl .error input#id_name {margin-right: 170px;}
2  theme/base/style/course.css
@@ -27,7 +27,7 @@
27 27
 .path-course-view li.activity form.togglecompletion .ajaxworking {position:absolute;top:0; left:20px;width: 20px; height: 20px;background: url([[pix:i/ajaxloader]]) no-repeat;}
28 28
 .dir-rtl.path-course-view li.activity {margin-right:0px;margin-left:20px;}
29 29
 .dir-rtl.path-course-view li.activity form.togglecompletion,
30  
-.dir-rtl.path-course-view li.activity span.autocompletion {right:auto;left:-20px;}
  30
+.dir-rtl.path-course-view li.activity span.autocompletion {right:auto;right:-20px;}
31 31
 
32 32
 .section img.movetarget {height:16px;width:80px;}
33 33
 
6  theme/mymobile/renderers.php
@@ -380,7 +380,7 @@ public function login_info_footer() {
380 380
             return '';
381 381
         }
382 382
 
383  
-        $loginapge = ((string)$this->page->url === get_login_url());
  383
+        $loginpage = ((string)$this->page->url === get_login_url());
384 384
         $course = $this->page->course;
385 385
 
386 386
         if (session_is_loggedinas()) {
@@ -407,7 +407,7 @@ public function login_info_footer() {
407 407
             }
408 408
             if (isguestuser()) {
409 409
                 $loggedinas = $realuserinfo.get_string('loggedinasguest');
410  
-                if (!$loginapge) {
  410
+                if (!$loginpage) {
411 411
                     $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
412 412
                 }
413 413
             } else if (is_role_switched($course->id)) { // Has switched roles
@@ -421,7 +421,7 @@ public function login_info_footer() {
421 421
             }
422 422
         } else {
423 423
             $loggedinas = get_string('loggedinnot', 'moodle');
424  
-            if (!$loginapge) {
  424
+            if (!$loginpage) {
425 425
                 $loggedinas .= " (<a href=\"$loginurl\">".get_string('login').'</a>)';
426 426
             }
427 427
         }
2  theme/standard/style/core.css
@@ -277,6 +277,8 @@ h2.tag-heading {text-align:center;margin-left:auto;margin-right:auto;width:95%;}
277 277
 #tags-management-links,
278 278
 .tag .managelink {text-align:right;}
279 279
 table#tag-management-list {margin: 10px auto;width: 80%;}
  280
+#page-tag-index.dir-rtl .relatedpages {text-align:center;}
  281
+#page-tag-index.dir-rtl .user-box {float:right;}
280 282
 
281 283
 /**
282 284
  * Overriding base
4  version.php
@@ -30,10 +30,10 @@
30 30
 defined('MOODLE_INTERNAL') || die();
31 31
 
32 32
 
33  
-$version  = 2011111500.00;              // YYYYMMDD      = weekly release date of this DEV branch
  33
+$version  = 2011111800.00;              // YYYYMMDD      = weekly release date of this DEV branch
34 34
                                         //         RR    = release increments - 00 in DEV branches
35 35
                                         //           .XX = incremental changes
36 36
 
37  
-$release  = '2.2beta (Build: 20111115)';// Human-friendly version name
  37
+$release  = '2.2beta (Build: 20111118)';// Human-friendly version name
38 38
 
39 39
 $maturity = MATURITY_BETA;              // this version's maturity level
13  webservice/renderer.php
@@ -46,15 +46,24 @@ public function admin_authorised_user_selector(&$options) {
46 46
         $table->cellspacing = 0;
47 47
         $table->cellpadding = 0;
48 48
 
  49
+        // LTR/RTL support, for drawing button arrows in the right direction
  50
+        if (right_to_left()) {
  51
+            $addarrow = '▶';
  52
+            $removearrow = '◀';
  53
+        } else {
  54
+            $addarrow = '◀';
  55
+            $removearrow = '▶';
  56
+        }
  57
+
49 58
         //create the add and remove button
50 59
         $addinput = html_writer::empty_tag('input',
51 60
                         array('name' => 'add', 'id' => 'add', 'type' => 'submit',
52  
-                            'value' => '◀' . ' ' . get_string('add'),
  61
+                            'value' => $addarrow . ' ' . get_string('add'),
53 62
                             'title' => get_string('add')));
54 63
         $addbutton = html_writer::tag('div', $addinput, array('id' => 'addcontrols'));
55 64
         $removeinput = html_writer::empty_tag('input',
56 65
                         array('name' => 'remove', 'id' => 'remove', 'type' => 'submit',
57  
-                            'value' => '▶' . ' ' . get_string('remove'),
  66
+                            'value' => $removearrow . ' ' . get_string('remove'),
58 67
                             'title' => get_string('remove')));
59 68
         $removebutton = html_writer::tag('div', $removeinput, array('id' => 'removecontrols'));
60 69
 

0 notes on commit 967bc47

Please sign in to comment.
Something went wrong with that request. Please try again.