Merge branch 'MDL-30775-23' of git://github.com/mouneyrac/moodle into MOODLE_23_STABLE
authorDamyon Wiese <damyon@moodle.com>
Thu, 2 May 2013 08:22:48 +0000 (16:22 +0800)
committerDamyon Wiese <damyon@moodle.com>
Thu, 2 May 2013 08:22:48 +0000 (16:22 +0800)
47 files changed:
course/format/renderer.php
course/renderer.php
course/yui/toolboxes/toolboxes.js
lib/dml/oci_native_moodle_database.php
lib/dml/tests/dml_test.php
lib/editor/tinymce/lib.php
lib/form/select.php
lib/moodlelib.php
lib/portfolio/caller.php
lib/tests/weblib_test.php
lib/weblib.php
message/output/jabber/message_output_jabber.php
mod/assign/mod_form.php
mod/assignment/mod_form.php
mod/book/mod_form.php
mod/chat/gui_basic/index.php
mod/chat/gui_header_js/chatinput.php
mod/chat/gui_header_js/users.php
mod/chat/gui_sockets/chatinput.php
mod/chat/mod_form.php
mod/choice/mod_form.php
mod/data/mod_form.php
mod/feedback/mod_form.php
mod/folder/mod_form.php
mod/forum/lib.php
mod/forum/post.php
mod/glossary/mod_form.php
mod/imscp/mod_form.php
mod/lesson/mod_form.php
mod/lti/locallib.php
mod/lti/mod_form.php
mod/lti/settings.php
mod/page/mod_form.php
mod/quiz/lib.php
mod/quiz/mod_form.php
mod/resource/mod_form.php
mod/scorm/mod_form.php
mod/scorm/report/reportlib.php
mod/url/mod_form.php
mod/wiki/mod_form.php
portfolio/googledocs/lib.php
portfolio/picasa/lib.php
question/type/match/edit_match_form.php
question/type/multichoice/renderer.php
question/type/multichoice/styles.css
theme/base/style/core.css
theme/canvas/style/core.css

index b045659..74718d9 100644 (file)
@@ -324,7 +324,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param array    $mods course modules indexed by id (from get_all_mods)
      * @return string HTML to output.
      */
-    private function section_activity_summary($section, $course, $mods) {
+    protected function section_activity_summary($section, $course, $mods) {
         if (empty($section->sequence)) {
             return '';
         }
index e6ed2b5..f771f9c 100644 (file)
@@ -191,18 +191,14 @@ class core_course_renderer extends plugin_renderer_base {
         $formcontent .= html_writer::start_tag('div', array('class' => 'alloptions'));
 
          // Activities
-        $activities = array_filter($modules, function($mod) {
-            return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM);
-        });
+        $activities = array_filter($modules, create_function('$mod', 'return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM);'));
         if (count($activities)) {
             $formcontent .= $this->course_modchooser_title('activities');
             $formcontent .= $this->course_modchooser_module_types($activities);
         }
 
         // Resources
-        $resources = array_filter($modules, function($mod) {
-            return ($mod->archetype === MOD_ARCHETYPE_RESOURCE);
-        });
+        $resources = array_filter($modules, create_function('$mod', 'return ($mod->archetype === MOD_ARCHETYPE_RESOURCE);'));
         if (count($resources)) {
             $formcontent .= $this->course_modchooser_title('resources');
             $formcontent .= $this->course_modchooser_module_types($resources);
index dd83903..18500d6 100644 (file)
@@ -509,7 +509,8 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                     'name'  : 'title',
                     'value' : titletext,
                     'autocomplete' : 'off',
-                    'aria-describedby' : 'id_editinstructions'
+                    'aria-describedby' : 'id_editinstructions',
+                    'maxLength' : '255'
                 })
                 .addClass('titleeditor');
             var editform = Y.Node.create('<form />')
index b62ac9b..b68877b 100644 (file)
@@ -1570,6 +1570,72 @@ class oci_native_moodle_database extends moodle_database {
         return " $s ";
     }
 
+    /**
+     * Constructs 'IN()' or '=' sql fragment
+     *
+     * Method overriding {@link moodle_database::get_in_or_equal} to be able to get
+     * more than 1000 elements working, to avoid ORA-01795. We use a pivoting technique
+     * to be able to transform the params into virtual rows, so the original IN()
+     * expression gets transformed into a subquery. Once more, be noted that we shouldn't
+     * be using ever get_in_or_equal() with such number of parameters (proper subquery and/or
+     * chunking should be used instead).
+     *
+     * @param mixed $items A single value or array of values for the expression.
+     * @param int $type Parameter bounding type : SQL_PARAMS_QM or SQL_PARAMS_NAMED.
+     * @param string $prefix Named parameter placeholder prefix (a unique counter value is appended to each parameter name).
+     * @param bool $equal True means we want to equate to the constructed expression, false means we don't want to equate to it.
+     * @param mixed $onemptyitems This defines the behavior when the array of items provided is empty. Defaults to false,
+     *              meaning throw exceptions. Other values will become part of the returned SQL fragment.
+     * @throws coding_exception | dml_exception
+     * @return array A list containing the constructed sql fragment and an array of parameters.
+     */
+    public function get_in_or_equal($items, $type=SQL_PARAMS_QM, $prefix='param', $equal=true, $onemptyitems=false) {
+        list($sql, $params) = parent::get_in_or_equal($items, $type, $prefix,  $equal, $onemptyitems);
+
+        // Less than 1000 elements, nothing to do.
+        if (count($params) < 1000) {
+            return array($sql, $params); // Return unmodified.
+        }
+
+        // Extract the interesting parts of the sql to rewrite.
+        if (preg_match('!(^.*IN \()([^\)]*)(.*)$!', $sql, $matches) === false) {
+            return array($sql, $params); // Return unmodified.
+        }
+
+        $instart = $matches[1];
+        $insql = $matches[2];
+        $inend = $matches[3];
+        $newsql = '';
+
+        // Some basic verification about the matching going ok.
+        $insqlarr = explode(',', $insql);
+        if (count($insqlarr) !== count($params)) {
+            return array($sql, $params); // Return unmodified.
+        }
+
+        // Arrived here, we need to chunk and pivot the params, building a new sql (params remain the same).
+        $addunionclause = false;
+        while ($chunk = array_splice($insqlarr, 0, 125)) { // Each chunk will handle up to 125 (+125 +1) elements (DECODE max is 255).
+            $chunksize = count($chunk);
+            if ($addunionclause) {
+                $newsql .= "\n    UNION ALL";
+            }
+            $newsql .= "\n        SELECT DECODE(pivot";
+            $counter = 1;
+            foreach ($chunk as $element) {
+                $newsql .= ",\n            {$counter}, " . trim($element);
+                $counter++;
+            }
+            $newsql .= ")";
+            $newsql .= "\n        FROM dual";
+            $newsql .= "\n        CROSS JOIN (SELECT LEVEL AS pivot FROM dual CONNECT BY LEVEL <= {$chunksize})";
+            $addunionclause = true;
+        }
+
+        // Rebuild the complete IN() clause and return it.
+        return array($instart . $newsql . $inend, $params);
+    }
+
     /**
      * Returns the SQL for returning searching one string for the location of another.
      */
index b6321c5..e541b83 100644 (file)
@@ -4152,6 +4152,27 @@ class dml_testcase extends database_driver_testcase {
         $DB->insert_record($tablename, array('course' => 7, 'content' => 'xx', 'name'=>'1abc'));
         $this->assertEquals(count($DB->get_records_sql($sql, array(1))), 1);
         $this->assertEquals(count($DB->get_records_sql($sql, array("1"))), 1);
+
+        // Test get_in_or_equal() with a big number of elements. Note that ideally
+        // we should be detecting and warning about any use over, say, 200 elements
+        // and recommend to change code to use subqueries and/or chunks instead.
+        $currentcount = $DB->count_records($tablename);
+        $numelements = 10000; // Verify that we can handle 10000 elements (crazy!)
+        $values = range(1, $numelements);
+
+        list($insql, $inparams) = $DB->get_in_or_equal($values, SQL_PARAMS_QM); // With QM params.
+        $sql = "SELECT *
+                  FROM {{$tablename}}
+                 WHERE id $insql";
+        $results = $DB->get_records_sql($sql, $inparams);
+        $this->assertEquals($currentcount, count($results));
+
+        list($insql, $inparams) = $DB->get_in_or_equal($values, SQL_PARAMS_NAMED); // With NAMED params.
+        $sql = "SELECT *
+                  FROM {{$tablename}}
+                 WHERE id $insql";
+        $results = $DB->get_records_sql($sql, $inparams);
+        $this->assertEquals($currentcount, count($results));
     }
 
     function test_onelevel_commit() {
index af2f841..bc2ae26 100644 (file)
@@ -139,7 +139,7 @@ class tinymce_texteditor extends texteditor {
                     'apply_source_formatting' => true,
                     'remove_script_host' => false,
                     'entity_encoding' => "raw",
-                    'plugins' => "{$xmedia}advimage,lists,table,style,layer,advhr,advlink,emotions,inlinepopups,searchreplace,paste,directionality,fullscreen,moodlenolink,{$xemoticon}{$xdragmath}nonbreaking,contextmenu,insertdatetime,save,iespell,preview,print,noneditable,visualchars,xhtmlxtras,template,pagebreak,spellchecker",
+                    'plugins' => "{$xmedia}advimage,table,style,layer,advhr,advlink,emotions,inlinepopups,searchreplace,paste,directionality,fullscreen,moodlenolink,{$xemoticon}{$xdragmath}nonbreaking,contextmenu,insertdatetime,save,iespell,preview,print,noneditable,visualchars,xhtmlxtras,template,pagebreak,spellchecker",
                     'theme_advanced_font_sizes' => "1,2,3,4,5,6,7",
                     'theme_advanced_layout_manager' => "SimpleLayout",
                     'theme_advanced_toolbar_align' => "left",
index 22c8752..7832f02 100644 (file)
@@ -71,13 +71,19 @@ class MoodleQuickForm_select extends HTML_QuickForm_select{
      * @return string
      */
     function toHtml(){
+        $html = '';
+        if ($this->getMultiple()) {
+            // Adding an hidden field forces the browser to send an empty data even though the user did not
+            // select any element. This value will be cleaned up in self::exportValue() as it will not be part
+            // of the select options.
+            $html .= '<input type="hidden" name="'.$this->getName().'" value="_qf__force_multiselect_submission">';
+        }
         if ($this->_hiddenLabel){
             $this->_generateId();
-            return '<label class="accesshide" for="'.$this->getAttribute('id').'" >'.
-                        $this->getLabel().'</label>'.parent::toHtml();
-        } else {
-             return parent::toHtml();
+            $html .= '<label class="accesshide" for="'.$this->getAttribute('id').'" >'.$this->getLabel().'</label>';
         }
+        $html .= parent::toHtml();
+        return $html;
     }
 
     /**
index 5b70ae1..1ddfafb 100644 (file)
@@ -6603,10 +6603,6 @@ class core_string_manager implements string_manager {
      * @return boot true if exists
      */
     public function string_exists($identifier, $component) {
-       $identifier = clean_param($identifier, PARAM_STRINGID);
-        if (empty($identifier)) {
-            return false;
-        }
         $lang = current_language();
         $string = $this->load_component_strings($component, $lang);
         return isset($string[$identifier]);
@@ -7063,10 +7059,6 @@ class install_string_manager implements string_manager {
      * @return boot true if exists
      */
     public function string_exists($identifier, $component) {
-        $identifier = clean_param($identifier, PARAM_STRINGID);
-        if (empty($identifier)) {
-            return false;
-        }
         // simple old style hack ;)
         $str = get_string($identifier, $component);
         return (strpos($str, '[[') === false);
@@ -7312,8 +7304,7 @@ function get_string($identifier, $component = '', $a = NULL, $lazyload = false)
         return new lang_string($identifier, $component, $a);
     }
 
-    $identifier = clean_param($identifier, PARAM_STRINGID);
-    if (empty($identifier)) {
+    if (debugging('', DEBUG_DEVELOPER) && clean_param($identifier, PARAM_STRINGID) === '') {
         throw new coding_exception('Invalid string identifier. The identifier cannot be empty. Please fix your get_string() call.');
     }
 
@@ -11120,7 +11111,7 @@ class lang_string {
         // Check if we need to process the string
         if ($this->string === null) {
             // Check the quality of the identifier.
-            if (clean_param($this->identifier, PARAM_STRINGID) == '') {
+            if (debugging('', DEBUG_DEVELOPER) && clean_param($this->identifier, PARAM_STRINGID) === '') {
                 throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of the string identifier. Please check your string definition');
             }
 
index 1a3fd3e..bc08ec8 100644 (file)
@@ -513,11 +513,13 @@ abstract class portfolio_module_caller_base extends portfolio_caller_base {
     /**
      * Navigation passed to print_header.
      * Override this to do something more specific than the module view page
+     * like adding more links to the breadcrumb.
      *
      * @return array
      */
     public function get_navigation() {
-        $extranav = array('name' => $this->cm->name, 'link' => $this->get_return_url());
+        // No extra navigation by default, link to the course module already included.
+        $extranav = array();
         return array($extranav, $this->cm);
     }
 
index 4ac75de..6f94b08 100644 (file)
@@ -70,8 +70,27 @@ class web_testcase extends advanced_testcase {
     }
 
     function test_s() {
-        $this->assertEquals(s("This Breaks \" Strict"), "This Breaks &quot; Strict");
-        $this->assertEquals(s("This Breaks <a>\" Strict</a>"), "This Breaks &lt;a&gt;&quot; Strict&lt;/a&gt;");
+        // Special cases.
+        $this->assertSame('0', s(0));
+        $this->assertSame('0', s('0'));
+        $this->assertSame('0', s(false));
+        $this->assertSame('', s(null));
+
+        // Normal cases.
+        $this->assertEquals('This Breaks &quot; Strict', s('This Breaks " Strict'));
+        $this->assertEquals('This Breaks &lt;a&gt;&quot; Strict&lt;/a&gt;', s('This Breaks <a>" Strict</a>'));
+
+        // Unicode characters.
+        $this->assertEquals('Café', s('Café'));
+        $this->assertEquals('一, 二, 三', s('一, 二, 三'));
+
+        // Don't escape already-escaped numeric entities. (Note, this behaviour
+        // may not be desirable. Perhaps we should remove these tests and that
+        // functionality, but we can only do that if we understand why it was added.)
+        $this->assertEquals('An entity: &#x09ff;.', s('An entity: &#x09ff;.'));
+        $this->assertEquals('An entity: &#1073;.', s('An entity: &#1073;.'));
+        $this->assertEquals('An entity: &amp;amp;.', s('An entity: &amp;.'));
+        $this->assertEquals('Not an entity: &amp;amp;#x09ff;.', s('Not an entity: &amp;#x09ff;.'));
     }
 
     function test_format_text_email() {
index 6c8ebab..2c712a6 100644 (file)
@@ -85,19 +85,19 @@ define('URL_MATCH_EXACT', 2);
  * Returns $var with HTML characters (like "<", ">", etc.) properly quoted.
  * This function is very similar to {@link p()}
  *
- * @todo Remove obsolete param $obsolete if not used anywhere
- *
  * @param string $var the string potentially containing HTML characters
- * @param boolean $obsolete no longer used.
  * @return string
  */
-function s($var, $obsolete = false) {
+function s($var) {
 
-    if ($var === '0' or $var === false or $var === 0) {
+    if ($var === false) {
         return '0';
     }
 
-    return preg_replace("/&amp;#(\d+|x[0-7a-fA-F]+);/i", "&#$1;", htmlspecialchars($var, ENT_QUOTES, 'UTF-8', true));
+    // When we move to PHP 5.4 as a minimum version, change ENT_QUOTES on the
+    // next line to ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE, and remove the
+    // 'UTF-8' argument. Both bring a speed-increase.
+    return preg_replace('/&amp;#(\d+|x[0-9a-f]+);/i', '&#$1;', htmlspecialchars($var, ENT_QUOTES, 'UTF-8'));
 }
 
 /**
index c4c9974..199e2aa 100644 (file)
@@ -73,6 +73,9 @@ class message_output_jabber extends message_output {
 
         $conn = new XMPPHP_XMPP($CFG->jabberhost,$CFG->jabberport,$CFG->jabberusername,$CFG->jabberpassword,'moodle',$CFG->jabberserver);
 
+        // No need to track the presence during the sending message process.
+        $conn->track_presence = false;
+
         try {
             //$conn->useEncryption(false);
             $conn->connect();
index 4b9929f..80b1b7e 100644 (file)
@@ -57,6 +57,7 @@ class mod_assign_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('description', 'assign'));
 
index 56b407d..bc0818f 100644 (file)
@@ -45,6 +45,7 @@ class mod_assignment_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('description', 'assignment'));
 
index 8901645..6bf1dbc 100644 (file)
@@ -45,6 +45,7 @@ class mod_book_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro, get_string('moduleintro'));
 
         $alloptions = book_get_numbering_types();
index aa79bd5..e645b06 100644 (file)
@@ -44,7 +44,7 @@ $context = get_context_instance(CONTEXT_MODULE, $cm->id);
 require_login($course, false, $cm);
 require_capability('mod/chat:chat', $context);
 $PAGE->set_pagelayout('base');
-$PAGE->set_popup_notification_allowed(false); // No popup notifications in the chat window
+$PAGE->set_popup_notification_allowed(false);
 
 /// Check to see if groups are being used here
  if ($groupmode = groups_get_activity_groupmode($cm)) {   // Groups are being used
index 02545f5..9568534 100644 (file)
@@ -24,6 +24,7 @@ if (!$cm = get_coursemodule_from_instance('chat', $chat->id, $course->id)) {
 }
 
 $PAGE->set_url('/mod/chat/gui_header_js/chatinput.php', array('chat_sid'=>$chat_sid, 'chat_id'=>$chatid));
+$PAGE->set_popup_notification_allowed(false);
 
 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
 
index 246417c..29dc041 100644 (file)
@@ -9,6 +9,7 @@ $chat_sid   = required_param('chat_sid', PARAM_ALPHANUM);
 $beep       = optional_param('beep', 0, PARAM_INT);  // beep target
 
 $PAGE->set_url('/mod/chat/gui_header_js/users.php', array('chat_sid'=>$chat_sid));
+$PAGE->set_popup_notification_allowed(false);
 
 if (!$chatuser = $DB->get_record('chat_users', array('sid'=>$chat_sid))) {
     print_error('notlogged', 'chat');
index d0603c2..8a9d864 100644 (file)
@@ -8,6 +8,7 @@ require('../lib.php');
 $chat_sid = required_param('chat_sid', PARAM_ALPHANUM);
 
 $PAGE->set_url('/mod/chat/gui_sockets/chatinput.php', array('chat_sid'=>$chat_sid));
+$PAGE->set_popup_notification_allowed(false);
 
 if (!$chatuser = $DB->get_record('chat_users', array('sid'=>$chat_sid))) {
     print_error('notlogged', 'chat');
index 8602539..294d2cd 100644 (file)
@@ -22,6 +22,7 @@ class mod_chat_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('chatintro', 'chat'));
 
index 70812f6..04011a0 100644 (file)
@@ -22,6 +22,7 @@ class mod_choice_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('chatintro', 'chat'));
 
index c5f7120..f8451d2 100644 (file)
@@ -22,6 +22,7 @@ class mod_data_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('intro', 'data'));
 
index 6256de7..9edb6cf 100644 (file)
@@ -44,6 +44,7 @@ class mod_feedback_mod_form extends moodleform_mod {
         $mform->addElement('text', 'name', get_string('name', 'feedback'), array('size'=>'64'));
         $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true, get_string('description', 'feedback'));
 
index 212cb12..7500e2b 100644 (file)
@@ -44,6 +44,7 @@ class mod_folder_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro);
 
         //-------------------------------------------------------
index 8994e71..928fda4 100644 (file)
@@ -7060,21 +7060,26 @@ function forum_get_separate_modules($courseid) {
 }
 
 /**
- * @global object
- * @global object
- * @global object
- * @param object $forum
- * @param object $cm
- * @return bool
+ * Handles the situation where the user has reached the blocking or warning threshold.
+ * The function will either echo out a message, or throw an exception depending on the
+ * threshold reached (warning or blocked). If the forum passed is invalid false is
+ * returned, otherwise if no restriction is needed true is returned.
+ *
+ * @param int|stdClass $forum the forum id or the forum object
+ * @param stdClass $cm the course module
+ * @param bool $display do we want to echo out the message?
+ * @return bool returns false if $forum is invalid or true
+ *         if there is no message to show.
  */
-function forum_check_throttling($forum, $cm=null) {
+function forum_check_throttling($forum, $cm = null, $display = true) {
     global $USER, $CFG, $DB, $OUTPUT;
 
     if (is_numeric($forum)) {
         $forum = $DB->get_record('forum',array('id'=>$forum));
     }
+
     if (!is_object($forum)) {
-        return false;  // this is broken.
+        return false; // This is broken.
     }
 
     if (empty($forum->blockafter)) {
@@ -7092,18 +7097,18 @@ function forum_check_throttling($forum, $cm=null) {
     }
 
     $modcontext = get_context_instance(CONTEXT_MODULE, $cm->id);
-    if(has_capability('mod/forum:postwithoutthrottling', $modcontext)) {
+    if (has_capability('mod/forum:postwithoutthrottling', $modcontext)) {
         return true;
     }
 
-    // get the number of posts in the last period we care about
+    // Get the number of posts in the last period we care about.
     $timenow = time();
     $timeafter = $timenow - $forum->blockperiod;
 
-    $numposts = $DB->count_records_sql('SELECT COUNT(p.id) FROM {forum_posts} p'
-                                      .' JOIN {forum_discussions} d'
-                                      .' ON p.discussion = d.id WHERE d.forum = ?'
-                                      .' AND p.userid = ? AND p.created > ?', array($forum->id, $USER->id, $timeafter));
+    $numposts = $DB->count_records_sql('SELECT COUNT(p.id) FROM {forum_posts} p
+                                        JOIN {forum_discussions} d
+                                        ON p.discussion = d.id WHERE d.forum = ?
+                                        AND p.userid = ? AND p.created > ?', array($forum->id, $USER->id, $timeafter));
 
     $a = new stdClass();
     $a->blockafter = $forum->blockafter;
@@ -7113,11 +7118,12 @@ function forum_check_throttling($forum, $cm=null) {
     if ($forum->blockafter <= $numposts) {
         print_error('forumblockingtoomanyposts', 'error', $CFG->wwwroot.'/mod/forum/view.php?f='.$forum->id, $a);
     }
+
     if ($forum->warnafter <= $numposts) {
-        echo $OUTPUT->notification(get_string('forumblockingalmosttoomanyposts','forum',$a));
+        if ($display) {
+            echo $OUTPUT->notification(get_string('forumblockingalmosttoomanyposts', 'forum', $a));
+        }
     }
-
-
 }
 
 
index 51b837e..da522fc 100644 (file)
@@ -680,7 +680,11 @@ if ($fromform = $mform_post->get_data()) {
 
 
     } else if ($fromform->discussion) { // Adding a new post to an existing discussion
+        // Before we add this we must check that the user will not exceed the blocking threshold.
+        forum_check_throttling($forum, $cm, false);
+
         unset($fromform->groupid);
+
         $message = '';
         $addpost = $fromform;
         $addpost->forum=$forum->id;
@@ -728,7 +732,10 @@ if ($fromform = $mform_post->get_data()) {
         }
         exit;
 
-    } else {                     // Adding a new discussion
+    } else { // Adding a new discussion.
+        // Before we add this we must check that the user will not exceed the blocking threshold.
+        forum_check_throttling($forum, $cm, false);
+
         if (!forum_user_can_post_discussion($forum, $fromform->groupid, -1, $cm, $modcontext)) {
             print_error('cannotcreatediscussion', 'forum');
         }
@@ -864,7 +871,10 @@ if ($forum->type == 'qanda'
     echo $OUTPUT->notification(get_string('qandanotify','forum'));
 }
 
-forum_check_throttling($forum, $cm);
+// If we are not editing a post we need to check the posting threshold.
+if (!$edit) {
+    forum_check_throttling($forum, $cm);
+}
 
 if (!empty($parent)) {
     if (! $discussion = $DB->get_record('forum_discussions', array('id' => $parent->discussion))) {
index 4db6c90..5610534 100644 (file)
@@ -22,6 +22,7 @@ class mod_glossary_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         $this->add_intro_editor(true);
 
index 450ab5d..e62453d 100644 (file)
@@ -45,6 +45,7 @@ class mod_imscp_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro);
 
         //-------------------------------------------------------
index 7f82372..dd99e80 100644 (file)
@@ -89,6 +89,7 @@ class mod_lesson_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         // Create a text box that can be enabled/disabled for lesson time limit
         $timedgrp = array();
index 645ec15..63eaacb 100644 (file)
@@ -563,6 +563,23 @@ function lti_filter_get_types($course) {
     return $DB->get_records('lti_types', $filter);
 }
 
+/**
+ * Given an array of tools, filter them based on their state
+ *
+ * @param array $tools An array of lti_types records
+ * @param int $state One of the LTI_TOOL_STATE_* constants
+ * @return array
+ */
+function lti_filter_tool_types(array $tools, $state) {
+    $return = array();
+    foreach ($tools as $key => $tool) {
+        if ($tool->state == $state) {
+            $return[$key] = $tool;
+        }
+    }
+    return $return;
+}
+
 function lti_get_types_for_add_instance() {
     global $DB, $SITE, $COURSE;
 
index ec1b5bf..425c518 100644 (file)
@@ -67,6 +67,7 @@ class mod_lti_mod_form extends moodleform_mod {
         $mform->addElement('text', 'name', get_string('basicltiname', 'lti'), array('size'=>'64'));
         $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         // Adding the optional "intro" and "introformat" pair of fields
         $this->add_intro_editor(false, get_string('basicltiintro', 'lti'));
         $mform->setAdvanced('introeditor');
index b7d4f2c..a36a7c7 100644 (file)
@@ -66,21 +66,15 @@ if ($ADMIN->fulltree) {
 
     $types = lti_filter_get_types(get_site()->id);
 
-    $configuredtools = array_filter($types, function($value) {
-        return $value->state == LTI_TOOL_STATE_CONFIGURED;
-    });
+    $configuredtools = lti_filter_tool_types($types, LTI_TOOL_STATE_CONFIGURED);
 
     $configuredtoolshtml = lti_get_tool_table($configuredtools, 'lti_configured');
 
-    $pendingtools = array_filter($types, function($value) {
-        return $value->state == LTI_TOOL_STATE_PENDING;
-    });
+    $pendingtools = lti_filter_tool_types($types, LTI_TOOL_STATE_PENDING);
 
     $pendingtoolshtml = lti_get_tool_table($pendingtools, 'lti_pending');
 
-    $rejectedtools = array_filter($types, function($value) {
-        return $value->state == LTI_TOOL_STATE_REJECTED;
-    });
+    $rejectedtools = lti_filter_tool_types($types, LTI_TOOL_STATE_REJECTED);
 
     $rejectedtoolshtml = lti_get_tool_table($rejectedtools, 'lti_rejected');
 
index 9ec1287..b36c1f1 100644 (file)
@@ -47,6 +47,7 @@ class mod_page_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro);
 
         //-------------------------------------------------------
index e5b712b..d16b5c2 100644 (file)
@@ -729,18 +729,19 @@ function quiz_grade_item_update($quiz, $grades = null) {
             // NOTE: this is an extremely nasty hack! It is not a bug if this confirmation fails badly. --skodak.
             $confirm_regrade = optional_param('confirm_regrade', 0, PARAM_INT);
             if (!$confirm_regrade) {
-                $message = get_string('gradeitemislocked', 'grades');
-                $back_link = $CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id .
-                        '&amp;mode=overview';
-                $regrade_link = qualified_me() . '&amp;confirm_regrade=1';
-                echo $OUTPUT->box_start('generalbox', 'notice');
-                echo '<p>'. $message .'</p>';
-                echo $OUTPUT->container_start('buttons');
-                echo $OUTPUT->single_button($regrade_link, get_string('regradeanyway', 'grades'));
-                echo $OUTPUT->single_button($back_link,  get_string('cancel'));
-                echo $OUTPUT->container_end();
-                echo $OUTPUT->box_end();
-
+                if (!AJAX_SCRIPT) {
+                    $message = get_string('gradeitemislocked', 'grades');
+                    $back_link = $CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id .
+                            '&amp;mode=overview';
+                    $regrade_link = qualified_me() . '&amp;confirm_regrade=1';
+                    echo $OUTPUT->box_start('generalbox', 'notice');
+                    echo '<p>'. $message .'</p>';
+                    echo $OUTPUT->container_start('buttons');
+                    echo $OUTPUT->single_button($regrade_link, get_string('regradeanyway', 'grades'));
+                    echo $OUTPUT->single_button($back_link,  get_string('cancel'));
+                    echo $OUTPUT->container_end();
+                    echo $OUTPUT->box_end();
+                }
                 return GRADE_UPDATE_ITEM_LOCKED;
             }
         }
index 9c71ac8..83dde01 100644 (file)
@@ -69,6 +69,7 @@ class mod_quiz_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         // Introduction.
         $this->add_intro_editor(false, get_string('introduction', 'quiz'));
index 7b9d645..b3173f1 100644 (file)
@@ -55,6 +55,7 @@ class mod_resource_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro);
 
         //-------------------------------------------------------
index a9f61e6..f3adbf0 100644 (file)
@@ -43,6 +43,7 @@ class mod_scorm_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
 
         // Summary
         $this->add_intro_editor(true);
index 21aa851..d6d50c6 100644 (file)
@@ -69,14 +69,14 @@ function get_scorm_question_count($scormid) {
     $rs = $DB->get_recordset_select("scorm_scoes_track", $select, $params, 'element');
     $keywords = array("cmi.interactions_", ".id");
     if ($rs->valid()) {
-        // Done as interactions start at 0 (do only if we have something to report).
-        $count++;
         foreach ($rs as $record) {
             $num = trim(str_ireplace($keywords, '', $record->element));
             if (is_numeric($num) && $num > $count) {
                 $count = $num;
             }
         }
+        // Done as interactions start at 0 (do only if we have something to report).
+        $count++;
     }
     $rs->close(); // closing recordset
     return $count;
index 47d4251..bde836a 100644 (file)
@@ -45,6 +45,7 @@ class mod_url_mod_form extends moodleform_mod {
             $mform->setType('name', PARAM_CLEANHTML);
         }
         $mform->addRule('name', null, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         $this->add_intro_editor($config->requiremodintro);
 
         //-------------------------------------------------------
index ef5b269..53b4fd0 100644 (file)
@@ -53,6 +53,7 @@ class mod_wiki_mod_form extends moodleform_mod {
         $mform->addElement('text', 'name', get_string('wikiname', 'wiki'), array('size' => '64'));
         $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', $required, 'required', null, 'client');
+        $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
         // Adding the optional "intro" and "introformat" pair of fields
         $this->add_intro_editor(true, get_string('wikiintro', 'wiki'));
 
index a7b87d0..4325722 100644 (file)
@@ -44,8 +44,9 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
     }
 
     public function expected_time($callertime) {
-        // We trust what the portfolio says.
-        return $callertime;
+        // We're forcing this to be run 'interactively' because the plugin
+        // does not support running in cron.
+        return PORTFOLIO_TIME_LOW;
     }
 
     public function send_package() {
index fff8760..d760b12 100644 (file)
@@ -44,7 +44,9 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
     }
 
     public function expected_time($callertime) {
-        return $callertime;
+        // We're forcing this to be run 'interactively' because the plugin
+        // does not support running in cron.
+        return PORTFOLIO_TIME_LOW;
     }
 
     public function send_package() {
index 241c7ef..d0ad73c 100644 (file)
@@ -42,7 +42,7 @@ class qtype_match_edit_form extends question_edit_form {
         $repeated[] = $mform->createElement('editor', 'subquestions',
                 get_string('question'), array('rows'=>3), $this->editoroptions);
         $repeated[] = $mform->createElement('text', 'subanswers',
-                get_string('answer', 'question'), array('size'=>50));
+                get_string('answer', 'question'), array('size' => 50, 'maxlength' => 255));
         $repeatedoptions['subquestions']['type'] = PARAM_RAW;
         $repeatedoptions['subanswers']['type'] = PARAM_TEXT;
         $answersoption = 'subquestions';
index 99e4f8e..afae706 100644 (file)
@@ -227,8 +227,8 @@ class qtype_multichoice_single_renderer extends qtype_multichoice_renderer_base
             if (question_state::graded_state_for_fraction($ans->fraction) ==
                     question_state::$gradedright) {
                 return get_string('correctansweris', 'qtype_multichoice',
-                        $question->format_text($ans->answer, $ans->answerformat,
-                                $qa, 'question', 'answer', $ansid));
+                        $question->make_html_inline($question->format_text($ans->answer, $ans->answerformat,
+                                $qa, 'question', 'answer', $ansid)));
             }
         }
 
@@ -278,8 +278,8 @@ class qtype_multichoice_multi_renderer extends qtype_multichoice_renderer_base {
         $right = array();
         foreach ($question->answers as $ansid => $ans) {
             if ($ans->fraction > 0) {
-                $right[] = $question->format_text($ans->answer, $ans->answerformat,
-                        $qa, 'question', 'answer', $ansid);
+                $right[] = $question->make_html_inline($question->format_text($ans->answer, $ans->answerformat,
+                        $qa, 'question', 'answer', $ansid));
             }
         }
 
index c179bb8..4c689d1 100644 (file)
@@ -1,18 +1,9 @@
 .que.multichoice .answer .specificfeedback {
-    padding: 0 0.7em;
-    background: #FFF3BF;
-}
-.que.multichoice .answer .specificfeedback * {
     display: inline;
+    padding: 0 0.7em;
     background: #FFF3BF;
 }
-.que.multichoice .answer .specificfeedback script {
-    display: none;
-}
 .que.multichoice .answer div.r0,
 .que.multichoice .answer div.r1 {
     padding: 0.3em;
 }
-.que.multichoice .feedback .rightanswer * {
-    display: inline;
-}
index c746ff3..50ccadb 100644 (file)
@@ -1,7 +1,8 @@
 /**
- * Required to undo YUI resets that override input size
+ * Required to undo YUI resets that override input size, margin, etc.
  */
 input[type=text],input[type=password],textarea{width:auto;}
+input[type=checkbox],input[type=radio]{margin-right: 7px;}
 
 /* Fix for YUI overriding styles */
 strong{font-style:inherit;}em{font-weight:inherit;}
index eb4b2ea..3161b70 100644 (file)
@@ -76,11 +76,6 @@ body {
     padding-left: 0;
 }
 
-input[type="checkbox"],
-input[type="radio"] {
-    margin-right: 7px;
-}
-
 /* Calendar
 -------------------------*/
 
@@ -656,4 +651,4 @@ input[type="radio"] {
     margin: 10% auto;
 }
 
-.path-grade-report.dir-rtl #graded_users_selector .singleselect {margin: 0px;}
\ No newline at end of file
+.path-grade-report.dir-rtl #graded_users_selector .singleselect {margin: 0px;}