Merge branch 'MDL-53515-master' of git://github.com/merrill-oakland/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 29 Mar 2016 06:39:53 +0000 (14:39 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 29 Mar 2016 06:39:53 +0000 (14:39 +0800)
55 files changed:
group/lib.php
lang/en/group.php
lang/en/search.php
lib/amd/build/form-autocomplete.min.js
lib/amd/src/form-autocomplete.js
lib/behat/form_field/behat_form_select.php
lib/classes/event/grouping_group_assigned.php [new file with mode: 0644]
lib/classes/event/grouping_group_unassigned.php [new file with mode: 0644]
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/src/editor/js/clean.js
lib/modinfolib.php
lib/outputrenderers.php
mod/data/lib.php
mod/data/tests/search_test.php
mod/feedback/db/access.php
mod/feedback/db/upgrade.php
mod/feedback/import.php
mod/feedback/item/captcha/lib.php
mod/feedback/item/feedback_item_form_class.php
mod/feedback/item/info/lib.php
mod/feedback/item/label/label_form.php
mod/feedback/item/label/lib.php
mod/feedback/item/multichoice/lib.php
mod/feedback/item/multichoicerated/lib.php
mod/feedback/item/numeric/lib.php
mod/feedback/item/numeric/numeric_form.php
mod/feedback/item/textarea/lib.php
mod/feedback/item/textfield/lib.php
mod/feedback/item/textfield/textfield_form.php
mod/feedback/lang/en/feedback.php
mod/feedback/lib.php
mod/feedback/tests/behat/question_types.feature
mod/feedback/version.php
mod/forum/lib.php
mod/forum/tests/mail_test.php
mod/quiz/classes/structure.php
mod/quiz/db/upgrade.php
mod/quiz/tests/structure_test.php
mod/quiz/version.php
mod/scorm/datamodels/scorm_13.js
mod/scorm/datamodels/scorm_13lib.php
repository/s3/README_MOODLE.txt
repository/s3/S3.php
repository/s3/lib.php
repository/s3/thirdpartylibs.xml
repository/s3/version.php
search/classes/document.php
search/engine/solr/classes/document.php
search/engine/solr/classes/engine.php
search/engine/solr/classes/schema.php
search/engine/solr/tests/engine_test.php
search/templates/result.mustache
user/lib.php

index e0c0e4b..3f8de4e 100644 (file)
@@ -837,12 +837,21 @@ function groups_assign_grouping($groupingid, $groupid, $timeadded = null, $inval
     }
     $DB->insert_record('groupings_groups', $assign);
 
+    $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
     if ($invalidatecache) {
         // Invalidate the grouping cache for the course
-        $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
         cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
     }
 
+    // Trigger event.
+    $params = array(
+        'context' => context_course::instance($courseid),
+        'objectid' => $groupingid,
+        'other' => array('groupid' => $groupid)
+    );
+    $event = \core\event\grouping_group_assigned::create($params);
+    $event->trigger();
+
     return true;
 }
 
@@ -858,12 +867,21 @@ function groups_unassign_grouping($groupingid, $groupid, $invalidatecache = true
     global $DB;
     $DB->delete_records('groupings_groups', array('groupingid'=>$groupingid, 'groupid'=>$groupid));
 
+    $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
     if ($invalidatecache) {
         // Invalidate the grouping cache for the course
-        $courseid = $DB->get_field('groupings', 'courseid', array('id' => $groupingid));
         cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($courseid));
     }
 
+    // Trigger event.
+    $params = array(
+        'context' => context_course::instance($courseid),
+        'objectid' => $groupingid,
+        'other' => array('groupid' => $groupid)
+    );
+    $event = \core\event\grouping_group_unassigned::create($params);
+    $event->trigger();
+
     return true;
 }
 
index 464ee74..227f500 100644 (file)
@@ -76,6 +76,8 @@ $string['eventgroupmemberremoved'] = 'Group member removed';
 $string['eventgroupupdated'] = 'Group updated';
 $string['eventgroupingcreated'] = 'Grouping created';
 $string['eventgroupingdeleted'] = 'Grouping deleted';
+$string['eventgroupinggroupassigned'] = 'Group assigned to grouping';
+$string['eventgroupinggroupunassigned'] = 'Group unassigned from grouping';
 $string['eventgroupingupdated'] = 'Grouping updated';
 $string['existingmembers'] = 'Existing members: {$a}';
 $string['filtergroups'] = 'Filter groups by:';
index 4fa4529..b1e9455 100644 (file)
@@ -69,6 +69,7 @@ $string['matchingfiles'] = 'Matched from files:';
 $string['next'] = 'Next';
 $string['noindexmessage'] = 'Admin: There appears to be no search index. Please';
 $string['noresults'] = 'No results';
+$string['notitle'] = 'No title';
 $string['normalsearch'] = 'Normal search';
 $string['openedon'] = 'opened on';
 $string['optimize'] = 'Optimize';
index d024ddb..76fd2b9 100644 (file)
Binary files a/lib/amd/build/form-autocomplete.min.js and b/lib/amd/build/form-autocomplete.min.js differ
index 474708e..ba27f86 100644 (file)
@@ -111,6 +111,9 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification']
         }).fail(notification.exception);
         // Because this function get's called after changing the selection, this is a good place
         // to trigger a change notification.
+        if (typeof M.core_formchangechecker != 'undefined') {
+            M.core_formchangechecker.set_form_changed();
+        }
         originalSelect.change();
     };
 
index 880d061..20c3a6b 100644 (file)
@@ -76,7 +76,12 @@ class behat_form_select extends behat_form_field {
             $browser = \Moodle\BehatExtension\Driver\MoodleSelenium2Driver::getBrowser();
             if (!$singleselect && ($browser == 'phantomjs')) {
                 $script = "Syn.trigger('change', {}, {{ELEMENT}})";
-                $this->session->getDriver()->triggerSynScript($this->field->getXpath(), $script);
+                try {
+                    $this->session->getDriver()->triggerSynScript($this->field->getXpath(), $script);
+                } catch (Exception $e) {
+                    // No need to do anything if element has been removed by JS.
+                    // This is possible when inline editing element is used.
+                }
             }
             $this->session->wait(behat_base::TIMEOUT * 1000, behat_base::PAGE_READY_JS);
         }
diff --git a/lib/classes/event/grouping_group_assigned.php b/lib/classes/event/grouping_group_assigned.php
new file mode 100644 (file)
index 0000000..5deb9bd
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Group assigned to grouping event.
+ *
+ * @package    core
+ * @copyright  2016 Vadim Dvorovenko
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Group assigned to grouping event class.
+ *
+ * @package    core
+ * @since      Moodle 3.1
+ * @copyright  2016 Vadim Dvorovenko
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class grouping_group_assigned extends base {
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' assigned the group with id '{$this->other['groupid']}'" .
+                " to the grouping with id '$this->objectid'.";
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventgroupinggroupassigned', 'group');
+    }
+
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/group/assign.php', array('id' => $this->objectid));
+    }
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['crud'] = 'c';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+        $this->data['objecttable'] = 'groupings';
+    }
+
+    /**
+     * This is used when restoring course logs where it is required that we
+     * map the objectid to its new value in the new course.
+     *
+     * @return string the name of the restore mapping the objectid links to
+     */
+    public static function get_objectid_mapping() {
+        return array('db' => 'groupings', 'restore' => 'group');
+    }
+
+    /**
+     * This is used when restoring course logs where it is required that we
+     * map the information in 'other' to its new value in the new course.
+     *
+     * @return array an array of other values and their corresponding mapping
+     */
+    public static function get_other_mapping() {
+        $othermapped = array();
+        $othermapped['groupid'] = array('db' => 'groups', 'restore' => 'group');
+        return $othermapped;
+    }
+}
diff --git a/lib/classes/event/grouping_group_unassigned.php b/lib/classes/event/grouping_group_unassigned.php
new file mode 100644 (file)
index 0000000..6fe209e
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Group unassigned from grouping event.
+ *
+ * @package    core
+ * @copyright  2016 Vadim Dvorovenko
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core\event;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Group unassigned from grouping event class.
+ *
+ * @package    core
+ * @since      Moodle 3.1
+ * @copyright  2016 Vadim Dvorovenko
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class grouping_group_unassigned extends base {
+
+    /**
+     * Returns description of what happened.
+     *
+     * @return string
+     */
+    public function get_description() {
+        return "The user with id '$this->userid' unassigned the group with id '{$this->other['groupid']}'" .
+                " from the grouping with id '$this->objectid'.";
+    }
+
+    /**
+     * Return localised event name.
+     *
+     * @return string
+     */
+    public static function get_name() {
+        return get_string('eventgroupinggroupunassigned', 'group');
+    }
+
+    /**
+     * Get URL related to the action.
+     *
+     * @return \moodle_url
+     */
+    public function get_url() {
+        return new \moodle_url('/group/assign.php', array('id' => $this->objectid));
+    }
+
+    /**
+     * Init method.
+     *
+     * @return void
+     */
+    protected function init() {
+        $this->data['crud'] = 'd';
+        $this->data['edulevel'] = self::LEVEL_OTHER;
+        $this->data['objecttable'] = 'groupings';
+    }
+
+    /**
+     * This is used when restoring course logs where it is required that we
+     * map the objectid to its new value in the new course.
+     *
+     * @return string the name of the restore mapping the objectid links to
+     */
+    public static function get_objectid_mapping() {
+        return array('db' => 'groupings', 'restore' => 'group');
+    }
+
+    /**
+     * This is used when restoring course logs where it is required that we
+     * map the information in 'other' to its new value in the new course.
+     *
+     * @return array an array of other values and their corresponding mapping
+     */
+    public static function get_other_mapping() {
+        $othermapped = array();
+        $othermapped['groupid'] = array('db' => 'groups', 'restore' => 'group');
+        return $othermapped;
+    }
+}
index d5ed2a6..4efa43a 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 6d77779..b64c044 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index d15b0a7..3b9fe61 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index 0c37c58..5b86018 100644 (file)
@@ -290,6 +290,8 @@ EditorClean.prototype = {
             {regex: /(<[^>]*?style\s*?=\s*?")([^>"]*)(")/gi, replace: function(match, group1, group2, group3) {
                     // Remove MSO-blah, MSO:blah style attributes.
                     group2 = group2.replace(/(?:^|;)[\s]*MSO[-:](?:&[\w]*;|[^;"])*/gi,"");
+                    // Remove backgroud color style.
+                    group2 = group2.replace(/background-color:.*?;/gi,"");
                     return group1 + group2 + group3;
                 }},
             // Get all class attributes so we can work on them.
index ff0a4f7..23aeb8e 100644 (file)
@@ -250,7 +250,7 @@ class course_modinfo {
         $modnames = get_module_types_names($plural);
         $modnamesused = array();
         foreach ($this->get_cms() as $cmid => $mod) {
-            if (isset($modnames[$mod->modname]) && $mod->uservisible) {
+            if (!isset($modnamesused[$mod->modname]) && isset($modnames[$mod->modname]) && $mod->uservisible) {
                 $modnamesused[$mod->modname] = $modnames[$mod->modname];
             }
         }
index c20a16c..f866fe0 100644 (file)
@@ -3377,12 +3377,16 @@ EOD;
                                 array('class' => 'iconsmall')
                             ) . $value->title;
                         }
+
                         $al = new action_menu_link_secondary(
                             $value->url,
                             $pix,
                             $value->title,
                             array('class' => 'icon')
                         );
+                        if (!empty($value->titleidentifier)) {
+                            $al->attributes['data-title'] = $value->titleidentifier;
+                        }
                         $am->add($al);
                         break;
                 }
index a85601c..8882776 100644 (file)
@@ -3654,6 +3654,11 @@ function data_get_all_recordids($dataid, $selectdata = '', $params = null) {
  * @return array $recordids   An array of record ids.
  */
 function data_get_advance_search_ids($recordids, $searcharray, $dataid) {
+    // Check to see if we have any record IDs.
+    if (empty($recordids)) {
+        // Send back an empty search.
+        return array();
+    }
     $searchcriteria = array_keys($searcharray);
     // Loop through and reduce the IDs one search criteria at a time.
     foreach ($searchcriteria as $key) {
index f2bd376..1e54d95 100644 (file)
@@ -189,6 +189,9 @@ class data_advanced_search_sql_test extends advanced_testcase {
      * extra parameters. $alias is the field alias used in the sql query and $commaid
      * is a comma seperated string of record IDs.
      *
+     * Test 3.1: This tests that if no recordids are provided (In a situation where a search is done on an empty database)
+     * That an empty array is returned.
+     *
      * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
      * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
      * takes that information and does a search on the database, returning a record.
@@ -217,6 +220,10 @@ class data_advanced_search_sql_test extends advanced_testcase {
         $newrecordids = data_get_advance_search_ids($recordids, $this->recordsearcharray, $this->recorddata->id);
         $this->assertEquals($this->datarecordset, $newrecordids);
 
+        // Test 3.1
+        $resultrecordids = data_get_advance_search_ids(array(), $this->recordsearcharray, $this->recorddata->id);
+        $this->assertEmpty($resultrecordids);
+
         // Test 4
         $sortorder = 'ORDER BY r.timecreated ASC , r.id ASC';
         $html = data_get_advanced_search_sql('0', $this->recorddata, $newrecordids, '', $sortorder);
index 30c309a..ccf8639 100644 (file)
@@ -44,6 +44,7 @@ $capabilities = array(
         'contextlevel' => CONTEXT_MODULE,
         'archetypes' => array(
             'guest' => CAP_ALLOW,
+            'frontpage' => CAP_ALLOW,
             'student' => CAP_ALLOW,
             'teacher' => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
@@ -58,6 +59,7 @@ $capabilities = array(
         'captype' => 'write',
         'contextlevel' => CONTEXT_MODULE,
         'archetypes' => array(
+            'frontpage' => CAP_ALLOW,
             'student' => CAP_ALLOW
         )
     ),
index 6733a34..80a482f 100644 (file)
@@ -37,7 +37,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 function xmldb_feedback_upgrade($oldversion) {
-    global $CFG;
+    global $CFG, $DB;
 
     // Moodle v2.8.0 release upgrade line.
     // Put any upgrade step following this.
@@ -48,5 +48,14 @@ function xmldb_feedback_upgrade($oldversion) {
     // Moodle v3.0.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2016031600) {
+        // Remove labels from all 'captcha' and 'label' items.
+        $DB->execute('UPDATE {feedback_item} SET label = ? WHERE typ = ? OR typ = ?',
+                array('', 'captcha', 'label'));
+
+        // Data savepoint reached.
+        upgrade_mod_savepoint(true, 2016031600, 'feedback');
+    }
+
     return true;
 }
index 083ba26..1339afd 100644 (file)
@@ -208,6 +208,10 @@ function feedback_import_loaded_data(&$data, $feedbackid) {
         $newitem->typ = $typ;
         $newitem->name = trim($item['#']['ITEMTEXT'][0]['#']);
         $newitem->label = trim($item['#']['ITEMLABEL'][0]['#']);
+        if ($typ === 'captcha' || $typ === 'label') {
+            $newitem->label = '';
+            $newitem->name = '';
+        }
         $newitem->options = trim($item['#']['OPTIONS'][0]['#']);
         $newitem->presentation = trim($item['#']['PRESENTATION'][0]['#']);
         //check old types of radio, check, and so on
index 88847ef..66c2431 100644 (file)
@@ -55,7 +55,7 @@ class feedback_item_captcha extends feedback_item_base {
         $this->item->feedback = $feedback->id;
         $this->item->template = 0;
         $this->item->name = get_string('captcha', 'feedback');
-        $this->item->label = get_string('captcha', 'feedback');
+        $this->item->label = '';
         $this->item->presentation = '';
         $this->item->typ = $this->type;
         $this->item->hasvalue = $this->get_hasvalue();
@@ -139,8 +139,10 @@ class feedback_item_captcha extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name.$requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
 
     }
@@ -192,8 +194,10 @@ class feedback_item_captcha extends feedback_item_base {
 
             //print the question and label
             echo '<div class="feedback_item_label_'.$align.'">';
-            echo '('.$item->label.') ';
-            echo format_text($item->name.$requiredmark, true, false, false);
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
             $inputname = 'name="'.$item->typ.'_'.$item->id.'"';
             echo '<input type="hidden" value="'.$USER->sesskey.'" '.$inputname.' />';
             echo '</div>';
@@ -259,26 +263,19 @@ class feedback_item_captcha extends feedback_item_base {
      * @return void
      */
     public function print_item_show_value($item, $value = '') {
-        global $DB;
+        global $OUTPUT;
 
         $align = right_to_left() ? 'right' : 'left';
 
-        $cmid = 0;
-        $feedbackid = $item->feedback;
-        if ($feedbackid > 0) {
-            $feedback = $DB->get_record('feedback', array('id'=>$feedbackid));
-            if ($cm = get_coursemodule_from_instance("feedback", $feedback->id, $feedback->course)) {
-                $cmid = $cm->id;
-            }
-        }
-
         $requiredmark = '<img class="req" title="'.get_string('requiredelement', 'form').'" alt="'.
             get_string('requiredelement', 'form').'" src="'.$OUTPUT->pix_url('req') .'" />';
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name.$requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
     }
 
index e44ec33..f9b16d8 100644 (file)
@@ -76,7 +76,7 @@ abstract class feedback_item_form extends moodleform {
         $mform->setType('template', PARAM_INT);
 
         $mform->setType('name', PARAM_RAW);
-        $mform->setType('label', PARAM_ALPHANUM);
+        $mform->setType('label', PARAM_NOTAGS);
 
         $mform->addElement('hidden', 'typ', $this->type);
         $mform->setType('typ', PARAM_ALPHA);
index de56497..7583b79 100644 (file)
@@ -142,7 +142,7 @@ class feedback_item_info extends feedback_item_base {
         if (!isset($value->value)) {
             return '';
         }
-        return userdate($value->value);
+        return $item->presentation == 1 ? userdate($value->value) : $value->value;
     }
 
     public function print_analysed($item, $itemnr = '', $groupid = false, $courseid = false) {
@@ -150,7 +150,11 @@ class feedback_item_info extends feedback_item_base {
         $data = $analysed_item->data;
         if (is_array($data)) {
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$item->name;
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
             echo '</th></tr>';
             $sizeofdata = count($data);
             for ($i = 0; $i < $sizeofdata; $i++) {
@@ -241,12 +245,14 @@ class feedback_item_info extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name.$requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -330,7 +336,7 @@ class feedback_item_info extends feedback_item_base {
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<span class="'.$highlight.'">';
-            echo format_text($item->name.$requiredmark, true, false, false);
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</span>';
         echo '</div>';
 
@@ -363,8 +369,10 @@ class feedback_item_info extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-            echo '('.$item->label.') ';
-            echo format_text($item->name . $requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
 
         //print the presentation
index b015cd1..3509908 100644 (file)
@@ -35,7 +35,7 @@ class feedback_label_form extends feedback_item_form {
         $mform->setType('required', PARAM_INT);
         $mform->addElement('hidden', 'name', 'label');
         $mform->setType('template', PARAM_ALPHA);
-        $mform->addElement('hidden', 'label', '-');
+        $mform->addElement('hidden', 'label', '');
         $mform->setType('label', PARAM_ALPHA);
 
         $mform->addElement('header', 'general', get_string($this->type, 'feedback'));
index 6b6d449..d4ca8e0 100644 (file)
@@ -184,7 +184,7 @@ class feedback_item_label extends feedback_item_base {
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
index c8df4aa..5835b9b 100644 (file)
@@ -231,7 +231,11 @@ class feedback_item_multichoice extends feedback_item_base {
         if ($analysed_item) {
             $itemname = $analysed_item[1];
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$itemname;
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo $itemname;
             echo '</th></tr>';
 
             $analysed_vals = $analysed_item[2];
@@ -320,12 +324,14 @@ class feedback_item_multichoice extends feedback_item_base {
         if ($info->subtype == 'd') {
             echo '<label for="'. $item->typ . '_' . $item->id .'">';
         }
-        echo '('.$item->label.') ';
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
         echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -425,7 +431,7 @@ class feedback_item_multichoice extends feedback_item_base {
         echo '<div class="feedback_item_label_'.$align.'">';
         if ($info->subtype == 'd') {
             echo '<label for="'. $inputname .'">';
-            echo format_text($item->name.$requiredmark, true, false, false);
+            echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
             if ($highlightrequire AND $item->required AND (count($values) == 0 OR $values[0] == '' OR $values[0] == 0)) {
                 echo '<br class="error"><span id="id_error_'.$inputname.'" class="error"> '.get_string('err_required', 'form').
                     '</span><br id="id_error_break_'.$inputname.'" class="error" >';
@@ -536,7 +542,9 @@ class feedback_item_multichoice extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-        echo '('.$item->label.') ';
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
         echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
 
index 79c2078..0eff14e 100644 (file)
@@ -206,7 +206,11 @@ class feedback_item_multichoicerated extends feedback_item_base {
         $analysed_item = $this->get_analysed($item, $groupid, $courseid);
         if ($analysed_item) {
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$analysed_item[1];
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo $analysed_item[1];
             echo '</th></tr>';
             $analysed_vals = $analysed_item[2];
             $pixnr = 0;
@@ -305,12 +309,14 @@ class feedback_item_multichoicerated extends feedback_item_base {
         if ($info->subtype == 'd') {
             echo '<label for="'. $item->typ . '_' . $item->id .'">';
         }
-        echo '('.$item->label.') ';
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
         echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -356,7 +362,7 @@ class feedback_item_multichoicerated extends feedback_item_base {
         echo '<div class="feedback_item_label_'.$align.'">';
         if ($info->subtype == 'd') {
             echo '<label for="'. $inputname .'">';
-            echo format_text($item->name.$requiredmark, true, false, false);
+            echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
             if ($highlightrequire AND $item->required AND intval($value) <= 0) {
                 echo '<br class="error"><span id="id_error_'.$inputname.'" class="error"> '.get_string('err_required', 'form').
                     '</span><br id="id_error_break_'.$inputname.'" class="error" >';
@@ -403,8 +409,10 @@ class feedback_item_multichoicerated extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-            echo '('.$item->label.') ';
-            echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
 
         //print the presentation
index fadd246..3a37322 100644 (file)
@@ -19,21 +19,12 @@ require_once($CFG->dirroot.'/mod/feedback/item/feedback_item_class.php');
 
 class feedback_item_numeric extends feedback_item_base {
     protected $type = "numeric";
-    public $sep_dec, $sep_thous;
     private $commonparams;
     private $item_form;
     private $item;
 
     public function init() {
-        $this->sep_dec = get_string('separator_decimal', 'feedback');
-        if (substr($this->sep_dec, 0, 2) == '[[') {
-            $this->sep_dec = FEEDBACK_DECIMAL;
-        }
 
-        $this->sep_thous = get_string('separator_thousand', 'feedback');
-        if (substr($this->sep_thous, 0, 2) == '[[') {
-            $this->sep_thous = FEEDBACK_THOUSAND;
-        }
     }
 
     public function build_editform($item, $feedback, $cm) {
@@ -58,17 +49,13 @@ class feedback_item_numeric extends feedback_item_base {
 
         $range_from_to = explode('|', $item->presentation);
         if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
-            $range_from = str_replace(FEEDBACK_DECIMAL,
-                                $this->sep_dec,
-                                floatval($range_from_to[0]));
+            $range_from = $this->format_float($range_from_to[0]);
         } else {
             $range_from = '-';
         }
 
         if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
-            $range_to = str_replace(FEEDBACK_DECIMAL,
-                                $this->sep_dec,
-                                floatval($range_from_to[1]));
+            $range_to = $this->format_float($range_from_to[1]);
         } else {
             $range_to = '-';
         }
@@ -152,7 +139,7 @@ class feedback_item_numeric extends feedback_item_base {
                     $counter++;
                 }
             }
-            $avg = $counter > 0 ? $avg / $counter : 0;
+            $avg = $counter > 0 ? $avg / $counter : null;
             $analysed->data = $data;
             $analysed->avg = $avg;
         }
@@ -173,19 +160,23 @@ class feedback_item_numeric extends feedback_item_base {
 
         if (isset($values->data) AND is_array($values->data)) {
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$item->name;
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
             echo '</th></tr>';
 
             foreach ($values->data as $value) {
                 echo '<tr><td colspan="2" valign="top" align="left">';
-                echo '-&nbsp;&nbsp;'.number_format($value, 2, $this->sep_dec, $this->sep_thous);
+                echo '-&nbsp;&nbsp;'.$this->format_float($value);
                 echo '</td></tr>';
             }
 
             if (isset($values->avg)) {
-                $avg = number_format($values->avg, 2, $this->sep_dec, $this->sep_thous);
+                $avg = format_float($values->avg, 2);
             } else {
-                $avg = number_format(0, 2, $this->sep_dec, $this->sep_thous);
+                $avg = '-';
             }
             echo '<tr><td align="left" colspan="2"><b>';
             echo get_string('average', 'feedback').': '.$avg;
@@ -204,16 +195,23 @@ class feedback_item_numeric extends feedback_item_base {
         $data = $analysed_item->data;
         if (is_array($data)) {
 
-            //mittelwert anzeigen
+            // Export average.
             $worksheet->write_string($row_offset,
                                      2,
                                      get_string('average', 'feedback'),
                                      $xls_formats->value_bold);
 
-            $worksheet->write_number($row_offset + 1,
-                                     2,
-                                     $analysed_item->avg,
-                                     $xls_formats->value_bold);
+            if (isset($analysed_item->avg)) {
+                $worksheet->write_number($row_offset + 1,
+                                         2,
+                                         $analysed_item->avg,
+                                         $xls_formats->value_bold);
+            } else {
+                $worksheet->write_string($row_offset + 1,
+                                         2,
+                                         '',
+                                         $xls_formats->value_bold);
+            }
             $row_offset++;
         }
         $row_offset++;
@@ -241,14 +239,14 @@ class feedback_item_numeric extends feedback_item_base {
         if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
             $range_from = floatval($range_from_to[0]);
         } else {
-            $range_from = 0;
+            $range_from = '-';
         }
 
         //get the max-value
         if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
             $range_to = floatval($range_from_to[1]);
         } else {
-            $range_to = 0;
+            $range_to = '-';
         }
 
         $requiredmark = ($item->required == 1) ? $strrequiredmark : '';
@@ -256,13 +254,15 @@ class feedback_item_numeric extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name . $requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             $params = array('id'=>$item->dependitem);
             if ($dependitem = $DB->get_record('feedback_item', $params)) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -270,17 +270,17 @@ class feedback_item_numeric extends feedback_item_base {
         switch(true) {
             case ($range_from === '-' AND is_numeric($range_to)):
                 echo ' ('.get_string('maximal', 'feedback').
-                        ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                        ': '.$this->format_float($range_to).')';
                 break;
             case (is_numeric($range_from) AND $range_to === '-'):
                 echo ' ('.get_string('minimal', 'feedback').
-                        ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).')';
+                        ': '.$this->format_float($range_from).')';
                 break;
             case ($range_from === '-' AND $range_to === '-'):
                 break;
             default:
-                echo ' ('.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).
-                        ' - '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                echo ' ('.$this->format_float($range_from).
+                        ' - '.$this->format_float($range_to).')';
                 break;
         }
         echo '</span>';
@@ -301,6 +301,22 @@ class feedback_item_numeric extends feedback_item_base {
         echo '</div>';
     }
 
+    /**
+     * Prints the float nicely in the localized format
+     *
+     * Similar to format_float() but automatically calculates the number of decimal places
+     *
+     * @param float $value The float to print
+     * @return string
+     */
+    protected function format_float($value) {
+        if (!is_numeric($value)) {
+            return null;
+        }
+        $decimal = is_int($value) ? 0 : strcspn(strrev($value), '.');
+        return format_float($value, $decimal);
+    }
+
     /**
      * print the item at the complete-page of feedback
      *
@@ -323,14 +339,14 @@ class feedback_item_numeric extends feedback_item_base {
         if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
             $range_from = floatval($range_from_to[0]);
         } else {
-            $range_from = 0;
+            $range_from = '-';
         }
 
         //get the max-value
         if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
             $range_to = floatval($range_from_to[1]);
         } else {
-            $range_to = 0;
+            $range_to = '-';
         }
 
         $requiredmark = ($item->required == 1) ? $strrequiredmark : '';
@@ -339,22 +355,22 @@ class feedback_item_numeric extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-        echo format_text($item->name . $requiredmark, true, false, false);
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '<span class="feedback_item_numinfo">';
         switch(true) {
             case ($range_from === '-' AND is_numeric($range_to)):
                 echo ' ('.get_string('maximal', 'feedback').
-                        ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                        ': '.$this->format_float($range_to).')';
                 break;
             case (is_numeric($range_from) AND $range_to === '-'):
                 echo ' ('.get_string('minimal', 'feedback').
-                        ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).')';
+                        ': '.$this->format_float($range_from).')';
                 break;
             case ($range_from === '-' AND $range_to === '-'):
                 break;
             default:
-                echo ' ('.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).
-                        ' - '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                echo ' ('.$this->format_float($range_from).
+                        ' - '.$this->format_float($range_to).')';
                 break;
         }
         echo '</span>';
@@ -399,34 +415,36 @@ class feedback_item_numeric extends feedback_item_base {
         if (isset($range_from_to[0]) AND is_numeric($range_from_to[0])) {
             $range_from = floatval($range_from_to[0]);
         } else {
-            $range_from = 0;
+            $range_from = '-';
         }
         //get the max-value
         if (isset($range_from_to[1]) AND is_numeric($range_from_to[1])) {
             $range_to = floatval($range_from_to[1]);
         } else {
-            $range_to = 0;
+            $range_to = '-';
         }
         $requiredmark = ($item->required == 1) ? $strrequiredmark : '';
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name . $requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         switch(true) {
             case ($range_from === '-' AND is_numeric($range_to)):
                 echo ' ('.get_string('maximal', 'feedback').
-                    ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                    ': '.$this->format_float($range_to).')';
                 break;
             case (is_numeric($range_from) AND $range_to === '-'):
                 echo ' ('.get_string('minimal', 'feedback').
-                    ': '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).')';
+                    ': '.$this->format_float($range_from).')';
                 break;
             case ($range_from === '-' AND $range_to === '-'):
                 break;
             default:
-                echo ' ('.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_from).
-                    ' - '.str_replace(FEEDBACK_DECIMAL, $this->sep_dec, $range_to).')';
+                echo ' ('.$this->format_float($range_from).
+                    ' - '.$this->format_float($range_to).')';
                 break;
         }
         echo '</div>';
@@ -435,7 +453,7 @@ class feedback_item_numeric extends feedback_item_base {
         echo '<div class="feedback_item_presentation_'.$align.'">';
         echo $OUTPUT->box_start('generalbox boxalign'.$align);
         if (is_numeric($value)) {
-            $str_num_value = number_format($value, 2, $this->sep_dec, $this->sep_thous);
+            $str_num_value = $this->format_float($value);
         } else {
             $str_num_value = '&nbsp;';
         }
@@ -445,7 +463,7 @@ class feedback_item_numeric extends feedback_item_base {
     }
 
     public function check_value($value, $item) {
-        $value = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $value);
+        $value = unformat_float($value, true);
         //if the item is not required, so the check is true if no value is given
         if ((!isset($value) OR $value == '') AND $item->required != 1) {
             return true;
@@ -491,7 +509,7 @@ class feedback_item_numeric extends feedback_item_base {
     }
 
     public function create_value($data) {
-        $data = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $data);
+        $data = unformat_float($data, true);
 
         if (is_numeric($data)) {
             $data = floatval($data);
@@ -512,14 +530,14 @@ class feedback_item_numeric extends feedback_item_base {
     }
 
     public function get_presentation($data) {
-        $num1 = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $data->numericrangefrom);
+        $num1 = unformat_float($data->numericrangefrom, true);
         if (is_numeric($num1)) {
             $num1 = floatval($num1);
         } else {
             $num1 = '-';
         }
 
-        $num2 = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $data->numericrangeto);
+        $num2 = unformat_float($data->numericrangeto, true);
         if (is_numeric($num2)) {
             $num2 = floatval($num2);
         } else {
@@ -546,11 +564,11 @@ class feedback_item_numeric extends feedback_item_base {
     }
 
     public function value_type() {
-        return PARAM_FLOAT;
+        return PARAM_TEXT;
     }
 
     public function clean_input_value($value) {
-        $value = str_replace($this->sep_dec, FEEDBACK_DECIMAL, $value);
+        $value = unformat_float($value, true);
         if (!is_numeric($value)) {
             if ($value == '') {
                 return null; //an empty string should be null
@@ -558,6 +576,6 @@ class feedback_item_numeric extends feedback_item_base {
                 return clean_param($value, PARAM_TEXT); //we have to know the value if it is wrong
             }
         }
-        return clean_param($value, $this->value_type());
+        return clean_param($value, PARAM_FLOAT);
     }
 }
index 449d1b7..67ca019 100644 (file)
@@ -44,13 +44,13 @@ class feedback_numeric_form extends feedback_item_form {
                             'rangefrom',
                             get_string('numeric_range_from', 'feedback'),
                             array('size'=>10, 'maxlength'=>10));
-        $mform->setType('rangefrom', PARAM_INT);
+        $mform->setType('rangefrom', PARAM_RAW);
 
         $mform->addElement('text',
                             'rangeto',
                             get_string('numeric_range_to', 'feedback'),
                             array('size'=>10, 'maxlength'=>10));
-        $mform->setType('rangeto', PARAM_INT);
+        $mform->setType('rangeto', PARAM_RAW);
 
         parent::definition();
         $this->set_data($item);
@@ -62,19 +62,13 @@ class feedback_numeric_form extends feedback_item_form {
             return false;
         }
 
-        $itemobj = new feedback_item_numeric();
-
-        $num1 = str_replace($itemobj->sep_dec, FEEDBACK_DECIMAL, $item->rangefrom);
-        if (is_numeric($num1)) {
-            $num1 = floatval($num1);
-        } else {
+        $num1 = unformat_float($item->rangefrom, true);
+        if ($num1 === false || $num1 === null) {
             $num1 = '-';
         }
 
-        $num2 = str_replace($itemobj->sep_dec, FEEDBACK_DECIMAL, $item->rangeto);
-        if (is_numeric($num2)) {
-            $num2 = floatval($num2);
-        } else {
+        $num2 = unformat_float($item->rangeto, true);
+        if ($num2 === false || $num2 === null) {
             $num2 = '-';
         }
 
index 66d76ff..bfb2f0c 100644 (file)
@@ -151,7 +151,11 @@ class feedback_item_textarea extends feedback_item_base {
         $values = feedback_get_group_values($item, $groupid, $courseid);
         if ($values) {
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$item->name;
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
             echo '</th></tr>';
             foreach ($values as $value) {
                 echo '<tr>';
@@ -208,12 +212,14 @@ class feedback_item_textarea extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name.$requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -254,7 +260,7 @@ class feedback_item_textarea extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-            echo format_text($item->name . $requiredmark, true, false, false);
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($highlightrequire AND $item->required AND strval($value) == '') {
             echo '<br class="error"><span id="id_error_'.$inputname.'" class="error"> '.get_string('err_required', 'form').
                 '</span><br id="id_error_break_'.$inputname.'" class="error" >';
@@ -294,8 +300,10 @@ class feedback_item_textarea extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-            echo '('.$item->label.') ';
-            echo format_text($item->name . $requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
 
         //print the presentation
index 77027c1..bcc1d89 100644 (file)
@@ -55,7 +55,7 @@ class feedback_item_textfield extends feedback_item_base {
             $itemsize = 30;
         }
 
-        $itemlength = isset($size_and_length[1]) ? $size_and_length[1] : 5;
+        $itemlength = isset($size_and_length[1]) ? $size_and_length[1] : 255;
 
         $item->itemsize = $itemsize;
         $item->itemmaxlength = $itemlength;
@@ -147,7 +147,11 @@ class feedback_item_textfield extends feedback_item_base {
         $values = feedback_get_group_values($item, $groupid, $courseid);
         if ($values) {
             echo '<tr><th colspan="2" align="left">';
-            echo $itemnr.'&nbsp;('.$item->label.') '.$item->name;
+            echo $itemnr . ' ';
+            if (strval($item->label) !== '') {
+                echo '('. format_string($item->label).') ';
+            }
+            echo format_text($item->name, FORMAT_HTML, array('noclean' => true, 'para' => false));
             echo '</th></tr>';
             foreach ($values as $value) {
                 echo '<tr><td colspan="2" valign="top" align="left">';
@@ -198,12 +202,14 @@ class feedback_item_textfield extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-        echo '('.$item->label.') ';
-        echo format_text($item->name.$requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($item->dependitem) {
             if ($dependitem = $DB->get_record('feedback_item', array('id'=>$item->dependitem))) {
                 echo ' <span class="feedback_depend">';
-                echo '('.$dependitem->label.'-&gt;'.$item->dependvalue.')';
+                echo '('.format_string($dependitem->label).'-&gt;'.$item->dependvalue.')';
                 echo '</span>';
             }
         }
@@ -245,7 +251,7 @@ class feedback_item_textfield extends feedback_item_base {
         $inputname = $item->typ . '_' . $item->id;
         echo '<div class="feedback_item_label_'.$align.'">';
         echo '<label for="'. $inputname .'">';
-            echo format_text($item->name.$requiredmark, true, false, false);
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         if ($highlightrequire AND $item->required AND strval($value) == '') {
             echo '<br class="error"><span id="id_error_'.$inputname.'" class="error"> '.get_string('err_required', 'form').
                 '</span><br id="id_error_break_'.$inputname.'" class="error" >';
@@ -285,8 +291,10 @@ class feedback_item_textfield extends feedback_item_base {
 
         //print the question and label
         echo '<div class="feedback_item_label_'.$align.'">';
-            echo '('.$item->label.') ';
-            echo format_text($item->name . $requiredmark, true, false, false);
+        if (strval($item->label) !== '') {
+            echo '('. format_string($item->label).') ';
+        }
+        echo format_text($item->name . $requiredmark, FORMAT_HTML, array('noclean' => true, 'para' => false));
         echo '</div>';
         echo $OUTPUT->box_start('generalbox boxalign'.$align);
         echo $value ? $value : '&nbsp;';
index 9361dff..da64f61 100644 (file)
@@ -44,10 +44,10 @@ class feedback_textfield_form extends feedback_item_form {
                             get_string('textfield_size', 'feedback').'&nbsp;',
                             array_slice(range(0, 255), 5, 255, true));
 
-        $mform->addElement('select',
+        $mform->addElement('text',
                             'itemmaxlength',
-                            get_string('textfield_maxlength', 'feedback').'&nbsp;',
-                            array_slice(range(0, 255), 5, 255, true));
+                            get_string('textfield_maxlength', 'feedback'));
+        $mform->setType('itemmaxlength', PARAM_INT);
 
         parent::definition();
         $this->set_data($item);
index c05b93a..79fb95f 100644 (file)
@@ -156,7 +156,8 @@ $string['mapcourses_help'] = 'Once you have selected the relevant course(s) from
 you can associate them with this feedback using map course(s). Multiple courses may be selected by holding down the Apple or Ctrl key whilst clicking on the course names. A course may be disassociated from a feedback at any time.';
 $string['mappedcourses'] = 'Mapped courses';
 $string['max_args_exceeded'] = 'Max 6 arguments can be handled, too many arguments for';
-$string['maximal'] = 'maximal';
+$string['minimal'] = 'minimum';
+$string['maximal'] = 'maximum';
 $string['messageprovider:message'] = 'Feedback reminder';
 $string['messageprovider:submission'] = 'Feedback notifications';
 $string['mode'] = 'Mode';
index f28d769..df09db1 100644 (file)
@@ -1450,7 +1450,9 @@ function feedback_get_depend_candidates_for_item($feedback, $item) {
     }
     //adding the choose-option
     foreach ($feedbackitems as $key => $val) {
-        $dependitems[$key] = $val;
+        if (trim(strval($val)) !== '') {
+            $dependitems[$key] = format_string($val);
+        }
     }
     return $dependitems;
 }
index d6dcbd6..0f506cc 100644 (file)
@@ -62,6 +62,7 @@ Feature: Test creating different types of feedback questions
     And I add a "Numeric answer" question to the feedback with:
       | Question               | this is a numeric answer |
       | Label                  | numeric                  |
+      | Range from             | 0                        |
       | Range to               | 100                      |
     And I add a "Short text answer" question to the feedback with:
       | Question               | this is a short text answer |
@@ -124,8 +125,8 @@ Feature: Test creating different types of feedback questions
     And I should see "1 (50.00 %)" in the "option l (1):" "table_row"
     And I should see "1 (50.00 %)" in the "option m (5):" "table_row"
     And I should see "Average: 3.00" in the "(multichoice4)" "table"
-    And I should see "35.00" in the "(numeric)" "table"
-    And I should see "71.00" in the "(numeric)" "table"
+    And I should see "35" in the "(numeric)" "table"
+    And I should see "71" in the "(numeric)" "table"
     And I should see "Average: 53.00" in the "(numeric)" "table"
     And I should see "no way" in the "(shorttext)" "table"
     And I should see "hello" in the "(shorttext)" "table"
index 567bc93..7abfd7a 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2015111600;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2016031600;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2015111000;    // Requires this Moodle version
 $plugin->component = 'mod_feedback';   // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 0;
index a1e9069..5aec1ba 100644 (file)
@@ -826,8 +826,8 @@ function forum_cron() {
                 // MS Outlook / Office uses poorly documented and non standard headers, including
                 // Thread-Topic which overrides the Subject and shouldn't contain Re: or Fwd: etc.
                 $a->subject = $discussion->name;
-                $postsubject = html_to_text(get_string('postmailsubject', 'forum', $a), 0);
-                $userfrom->customheaders[] = "Thread-Topic: $postsubject";
+                $threadtopic = html_to_text(get_string('postmailsubject', 'forum', $a), 0);
+                $userfrom->customheaders[] = "Thread-Topic: $threadtopic";
                 $userfrom->customheaders[] = "Thread-Index: " . substr($rootid, 1, 28);
 
                 // Send the post now!
index d979a4f..40f5be4 100644 (file)
@@ -184,6 +184,8 @@ class mod_forum_mail_testcase extends advanced_testcase {
         // Add a post to the discussion.
         $record = new stdClass();
         $record->course = $forum->course;
+        $strre = get_string('re', 'forum');
+        $record->subject = $strre . ' ' . $discussion->subject;
         $record->userid = $author->id;
         $record->forum = $forum->id;
         $record->discussion = $discussion->id;
@@ -834,6 +836,33 @@ class mod_forum_mail_testcase extends advanced_testcase {
         $this->assertEquals($expectedsubject, $message->subject);
     }
 
+    /**
+     * Test inital email and reply email subjects
+     */
+    public function test_subjects() {
+        $this->resetAfterTest(true);
+
+        $course = $this->getDataGenerator()->create_course();
+
+        $options = array('course' => $course->id, 'forcesubscribe' => FORUM_FORCESUBSCRIBE);
+        $forum = $this->getDataGenerator()->create_module('forum', $options);
+
+        list($author) = $this->helper_create_users($course, 1);
+        list($commenter) = $this->helper_create_users($course, 1);
+
+        $strre = get_string('re', 'forum');
+
+        // New posts should not have Re: in the subject.
+        list($discussion, $post) = $this->helper_post_to_forum($forum, $author);
+        $messages = $this->helper_run_cron_check_count($post, 2);
+        $this->assertNotContains($strre, $messages[0]->subject);
+
+        // Replies should have Re: in the subject.
+        $reply = $this->helper_post_to_discussion($forum, $discussion, $commenter);
+        $messages = $this->helper_run_cron_check_count($reply, 2);
+        $this->assertContains($strre, $messages[0]->subject);
+    }
+
     /**
      * dataProvider for test_forum_post_email_templates().
      */
index a9c4fe2..ba7f3a3 100644 (file)
@@ -708,6 +708,17 @@ class structure {
             $moveafterslotnumber = (int) $this->slots[$idmoveafter]->slot;
         }
 
+        // If the action came in as moving a slot to itself, normalise this to
+        // moving the slot to after the previous slot.
+        if ($moveafterslotnumber == $movingslotnumber) {
+            $moveafterslotnumber = $moveafterslotnumber - 1;
+        }
+
+        $followingslotnumber = $moveafterslotnumber + 1;
+        if ($followingslotnumber == $movingslotnumber) {
+            $followingslotnumber += 1;
+        }
+
         // Check the target page number is OK.
         if ($page == 0) {
             $page = 1;
@@ -716,16 +727,10 @@ class structure {
                 $page < 1) {
             throw new \coding_exception('The target page number is too small.');
         } else if (!$this->is_last_slot_in_quiz($moveafterslotnumber) &&
-                $page > $this->get_page_number_for_slot($moveafterslotnumber + 1)) {
+                $page > $this->get_page_number_for_slot($followingslotnumber)) {
             throw new \coding_exception('The target page number is too large.');
         }
 
-        // If the action came in as moving a slot to itself, normalise this to
-        // moving the slot to after the previosu slot.
-        if ($moveafterslotnumber == $movingslotnumber) {
-            $moveafterslotnumber = $moveafterslotnumber - 1;
-        }
-
         // Work out how things are being moved.
         $slotreorder = array();
         if ($moveafterslotnumber > $movingslotnumber) {
@@ -768,10 +773,12 @@ class structure {
                 $headingmoveafter = $movingslotnumber;
                 $headingmovebefore = $movingslotnumber + 2;
                 $headingmovedirection = -1;
-            } else {
+            } else if ($page < $movingslot->page) {
                 $headingmoveafter = $movingslotnumber - 1;
                 $headingmovebefore = $movingslotnumber + 1;
                 $headingmovedirection = 1;
+            } else {
+                return; // Nothing to do.
             }
         }
 
index c8590e3..d56585e 100644 (file)
@@ -165,5 +165,30 @@ function xmldb_quiz_upgrade($oldversion) {
     // Moodle v3.0.0 release upgrade line.
     // Put any upgrade step following this.
 
+    if ($oldversion < 2016032600) {
+        // Update quiz_sections to repair quizzes what were broken by MDL-53507.
+        $problemquizzes = $DB->get_records_sql("
+                SELECT quizid, MIN(firstslot) AS firstsectionfirstslot
+                FROM {quiz_sections}
+                GROUP BY quizid
+                HAVING MIN(firstslot) > 1");
+
+        if ($problemquizzes) {
+            $pbar = new progress_bar('upgradequizfirstsection', 500, true);
+            $total = count($problemquizzes);
+            $done = 0;
+            foreach ($problemquizzes as $problemquiz) {
+                $DB->set_field('quiz_sections', 'firstslot', 1,
+                        array('quizid' => $problemquiz->quizid,
+                        'firstslot' => $problemquiz->firstsectionfirstslot));
+                $done += 1;
+                $pbar->update($done, $total, "Fixing quiz layouts - {$done}/{$total}.");
+            }
+        }
+
+        // Quiz savepoint reached.
+        upgrade_mod_savepoint(true, 2016032600, 'quiz');
+    }
+
     return true;
 }
index 6210f81..a8e39f8 100644 (file)
@@ -515,7 +515,7 @@ class mod_quiz_structure_testcase extends advanced_testcase {
             ), $structure);
     }
 
-    public function test_move_slot_to_down_start_of_second_section() {
+    public function test_move_slot_down_to_start_of_second_section() {
         $quizobj = $this->create_test_quiz(array(
                 'Heading 1',
                 array('TF1', 1, 'truefalse'),
@@ -539,6 +539,63 @@ class mod_quiz_structure_testcase extends advanced_testcase {
             ), $structure);
     }
 
+    public function test_move_first_slot_down_to_start_of_page_2() {
+        $quizobj = $this->create_test_quiz(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 2, 'truefalse'),
+            ));
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+
+        $idtomove = $structure->get_question_in_slot(1)->slotid;
+        $structure->move_slot($idtomove, 0, '2');
+
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+        $this->assert_quiz_layout(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 1, 'truefalse'),
+            ), $structure);
+    }
+
+    public function test_move_first_slot_to_same_place_on_page_1() {
+        $quizobj = $this->create_test_quiz(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 2, 'truefalse'),
+            ));
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+
+        $idtomove = $structure->get_question_in_slot(1)->slotid;
+        $structure->move_slot($idtomove, 0, '1');
+
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+        $this->assert_quiz_layout(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 2, 'truefalse'),
+            ), $structure);
+    }
+
+    public function test_move_first_slot_to_before_page_1() {
+        $quizobj = $this->create_test_quiz(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 2, 'truefalse'),
+            ));
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+
+        $idtomove = $structure->get_question_in_slot(1)->slotid;
+        $structure->move_slot($idtomove, 0, '');
+
+        $structure = \mod_quiz\structure::create_for_quiz($quizobj);
+        $this->assert_quiz_layout(array(
+                'Heading 1',
+                array('TF1', 1, 'truefalse'),
+                array('TF2', 2, 'truefalse'),
+            ), $structure);
+    }
+
     public function test_move_slot_up_to_start_of_second_section() {
         $quizobj = $this->create_test_quiz(array(
                 'Heading 1',
index 3889380..c70290a 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2016032109;
+$plugin->version   = 2016032600;
 $plugin->requires  = 2015111000;
 $plugin->component = 'mod_quiz';
 $plugin->cron      = 60;
index e0569fd..d735172 100644 (file)
@@ -185,7 +185,7 @@ function SCORMapi1_3(def, cmiobj, cmiint, cmicommentsuser, cmicommentslms, scorm
             'cmi.interactions.n.result':{'pattern':CMIIndex, 'format':CMIResult, 'mod':'rw'},
             'cmi.interactions.n.latency':{'pattern':CMIIndex, 'format':CMITimespan, 'mod':'rw'},
             'cmi.interactions.n.description':{'pattern':CMIIndex, 'format':CMILangString250, 'mod':'rw'},
-            'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.exit'], 'mod':'r'},
+            'cmi.launch_data':{'defaultvalue':def[scoid]['cmi.launch_data'], 'mod':'r'},
             'cmi.learner_id':{'defaultvalue':def[scoid]['cmi.learner_id'], 'mod':'r'},
             'cmi.learner_name':{'defaultvalue':def[scoid]['cmi.learner_name'], 'mod':'r'},
             'cmi.learner_preference._children':{'defaultvalue':student_preference_children, 'mod':'r'},
index 0f79ace..71ee823 100644 (file)
@@ -1280,6 +1280,7 @@ function get_scorm_default (&$userdata, $scorm, $scoid, $attempt, $mode) {
     $def['cmi.suspend_data'] = scorm_isset($userdata, 'cmi.suspend_data');
     $def['cmi.time_limit_action'] = scorm_isset($userdata, 'timelimitaction');
     $def['cmi.total_time'] = scorm_isset($userdata, 'cmi.total_time', 'PT0H0M0S');
+    $def['cmi.launch_data'] = scorm_isset($userdata, 'datafromlms');
 
     return $def;
 }
index b387765..4f44dc3 100644 (file)
@@ -3,7 +3,6 @@
 Amazon S3 PHP Class
 
 Cloned from git://github.com/tpyo/amazon-s3-php-class.git
-At commit 8413f6f70ad3bb79ae756958d4ba2238514b00af
 
 https://github.com/tpyo/amazon-s3-php-class
 http://undesigned.org.za/2007/10/22/amazon-s3-php-class
index 0b1564b..d8048c7 100644 (file)
@@ -32,7 +32,7 @@
 * Amazon S3 PHP class
 *
 * @link http://undesigned.org.za/2007/10/22/amazon-s3-php-class
-* @version 0.5.1-dev
+* @version 0.5.1
 */
 class S3
 {
@@ -56,7 +56,7 @@ class S3
         * @static
         */
        private static $__accessKey = null;
-       
+
        /**
         * AWS Secret Key
         *
@@ -65,7 +65,7 @@ class S3
         * @static
         */
        private static $__secretKey = null;
-       
+
        /**
         * SSL Client key
         *
@@ -74,7 +74,15 @@ class S3
         * @static
         */
        private static $__sslKey = null;
-       
+
+       /**
+        * Default delimiter to be used, for example while getBucket().
+        * @var string
+        * @access public
+        * @static
+        */
+       public static $defDelimiter = null;
+
        /**
         * AWS URI
         *
@@ -83,7 +91,7 @@ class S3
         * @static
         */
        public static $endpoint = 's3.amazonaws.com';
-       
+
        /**
         * Proxy information
         *
@@ -92,7 +100,7 @@ class S3
         * @static
         */
        public static $proxy = null;
-       
+
        /**
         * Connect using SSL?
         *
@@ -101,7 +109,7 @@ class S3
         * @static
         */
        public static $useSSL = false;
-       
+
        /**
         * Use SSL validation?
         *
@@ -110,7 +118,16 @@ class S3
         * @static
         */
        public static $useSSLValidation = true;
-       
+
+       /**
+        * Use SSL version
+        *
+        * @var const
+        * @access public
+        * @static
+        */
+       public static $useSSLVersion = CURL_SSLVERSION_TLSv1;
+
        /**
         * Use PHP exceptions?
         *
@@ -202,6 +219,7 @@ class S3
                self::$endpoint = $host;
        }
 
+
        /**
        * Set AWS access key and secret key
        *
@@ -416,6 +434,7 @@ class S3
                if ($marker !== null && $marker !== '') $rest->setParameter('marker', $marker);
                if ($maxKeys !== null && $maxKeys !== '') $rest->setParameter('max-keys', $maxKeys);
                if ($delimiter !== null && $delimiter !== '') $rest->setParameter('delimiter', $delimiter);
+               else if (!empty(self::$defDelimiter)) $rest->setParameter('delimiter', self::$defDelimiter);
                $response = $rest->getResponse();
                if ($response->error === false && $response->code !== 200)
                        $response->error = array('code' => $response->code, 'message' => 'Unexpected HTTP status');
@@ -561,6 +580,7 @@ class S3
                        self::__triggerError('S3::inputFile(): Unable to open input file: '.$file, __FILE__, __LINE__);
                        return false;
                }
+               clearstatcache(false, $file);
                return array('file' => $file, 'size' => filesize($file), 'md5sum' => $md5sum !== false ?
                (is_string($md5sum) ? $md5sum : base64_encode(md5_file($file, true))) : '');
        }
@@ -634,15 +654,18 @@ class S3
                if (isset($input['size']) && $input['size'] >= 0)
                        $rest->size = $input['size'];
                else {
-                       if (isset($input['file']))
+                       if (isset($input['file'])) {
+                               clearstatcache(false, $input['file']);
                                $rest->size = filesize($input['file']);
+                       }
                        elseif (isset($input['data']))
                                $rest->size = strlen($input['data']);
                }
 
                // Custom request headers (Content-Type, Content-Disposition, Content-Encoding)
                if (is_array($requestHeaders))
-                       foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
+                       foreach ($requestHeaders as $h => $v)
+                               strpos($h, 'x-amz-') === 0 ? $rest->setAmzHeader($h, $v) : $rest->setHeader($h, $v);
                elseif (is_string($requestHeaders)) // Support for legacy contentType parameter
                        $input['type'] = $requestHeaders;
 
@@ -797,7 +820,8 @@ class S3
        {
                $rest = new S3Request('PUT', $bucket, $uri, self::$endpoint);
                $rest->setHeader('Content-Length', 0);
-               foreach ($requestHeaders as $h => $v) $rest->setHeader($h, $v);
+               foreach ($requestHeaders as $h => $v)
+                               strpos($h, 'x-amz-') === 0 ? $rest->setAmzHeader($h, $v) : $rest->setHeader($h, $v);
                foreach ($metaHeaders as $h => $v) $rest->setAmzHeader('x-amz-meta-'.$h, $v);
                if ($storageClass !== self::STORAGE_CLASS_STANDARD) // Storage class
                        $rest->setAmzHeader('x-amz-storage-class', $storageClass);
@@ -2117,6 +2141,9 @@ final class S3Request
 
                if (S3::$useSSL)
                {
+                       // Set protocol version
+                       curl_setopt($curl, CURLOPT_SSLVERSION, S3::$useSSLVersion);
+
                        // SSL Validation can now be optional for those with broken OpenSSL installations
                        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, S3::$useSSLValidation ? 2 : 0);
                        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, S3::$useSSLValidation ? 1 : 0);
@@ -2292,6 +2319,7 @@ final class S3Request
        private function __dnsBucketName($bucket)
        {
                if (strlen($bucket) > 63 || preg_match("/[^a-z0-9\.-]/", $bucket) > 0) return false;
+               if (S3::$useSSL && strstr($bucket, '.') !== false) return false;
                if (strstr($bucket, '-.') !== false) return false;
                if (strstr($bucket, '..') !== false) return false;
                if (!preg_match("/^[0-9a-z]/", $bucket)) return false;
index efb9909..ea87af0 100644 (file)
 require_once($CFG->dirroot . '/repository/lib.php');
 require_once($CFG->dirroot . '/repository/s3/S3.php');
 
+// This constant is not defined in php 5.4. Set it to avoid errors.
+if (!defined('CURL_SSLVERSION_TLSv1')) {
+    define('CURL_SSLVERSION_TLSv1', 1);
+}
+
 /**
  * This is a repository class used to browse Amazon S3 content.
  *
index f53ed95..04bb560 100644 (file)
@@ -4,7 +4,7 @@
     <location>S3.php</location>
     <name>S3</name>
     <license>BSD</license>
-    <version>0.5.1-dev</version>
+    <version>0.5.1</version>
     <licenseversion></licenseversion>
   </library>
 </libraries>
index df6d1fa..8cba240 100644 (file)
@@ -26,6 +26,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2015111600;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2015111601;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2015111000;        // Requires this Moodle version
 $plugin->component = 'repository_s3';   // Full name of the plugin (used for diagnostics)
index 5f96c28..c030fef 100644 (file)
@@ -101,12 +101,12 @@ class document implements \renderable, \templatable {
             'indexed' => true
         ),
         'title' => array(
-            'type' => 'string',
+            'type' => 'text',
             'stored' => true,
             'indexed' => true
         ),
         'content' => array(
-            'type' => 'string',
+            'type' => 'text',
             'stored' => true,
             'indexed' => true
         ),
@@ -158,12 +158,12 @@ class document implements \renderable, \templatable {
             'indexed' => false
         ),
         'description1' => array(
-            'type' => 'string',
+            'type' => 'text',
             'stored' => true,
             'indexed' => true
         ),
         'description2' => array(
-            'type' => 'string',
+            'type' => 'text',
             'stored' => true,
             'indexed' => true
         )
@@ -381,6 +381,19 @@ class document implements \renderable, \templatable {
         return $string;
     }
 
+    /**
+     * Formats a text value for the search engine.
+     *
+     * Search engines may overwrite this method to apply restrictions, like limiting the size.
+     * The default behaviour is just returning the string.
+     *
+     * @param string $text
+     * @return string
+     */
+    public static function format_text_for_engine($text) {
+        return $text;
+    }
+
     /**
      * Returns a timestamp from the value stored in the search engine.
      *
@@ -489,9 +502,13 @@ class document implements \renderable, \templatable {
                 // Overwrite the timestamp with the engine dependant format.
                 $data[$fieldname] = static::format_time_for_engine($data[$fieldname]);
             } else if ($field['type'] === 'string') {
-                // Overwrite the timestamp with the engine dependant format.
+                // Overwrite the string with the engine dependant format.
                 $data[$fieldname] = static::format_string_for_engine($data[$fieldname]);
+            } else if ($field['type'] === 'text') {
+                // Overwrite the text with the engine dependant format.
+                $data[$fieldname] = static::format_text_for_engine($data[$fieldname]);
             }
+
         }
 
         $fields = static::$optionalfields + static::$enginefields;
@@ -503,8 +520,11 @@ class document implements \renderable, \templatable {
                 // Overwrite the timestamp with the engine dependant format.
                 $data[$fieldname] = static::format_time_for_engine($data[$fieldname]);
             } else if ($field['type'] === 'string') {
-                // Overwrite the timestamp with the engine dependant format.
+                // Overwrite the string with the engine dependant format.
                 $data[$fieldname] = static::format_string_for_engine($data[$fieldname]);
+            } else if ($field['type'] === 'text') {
+                // Overwrite the text with the engine dependant format.
+                $data[$fieldname] = static::format_text_for_engine($data[$fieldname]);
             }
         }
 
@@ -535,14 +555,14 @@ class document implements \renderable, \templatable {
      * @return array
      */
     public function export_for_template(\renderer_base $output) {
-
         list($componentname, $areaname) = \core_search\manager::extract_areaid_parts($this->get('areaid'));
 
+        $title = $this->is_set('title') ? $this->format_text($this->get('title')) : '';
         $data = [
             'courseurl' => new \moodle_url('/course/view.php?id=' . $this->get('courseid')),
             'coursefullname' => format_string($this->get('coursefullname'), true, array('context' => $this->get('contextid'))),
             'modified' => userdate($this->get('modified')),
-            'title' => format_string($this->get('title'), true, array('context' => $this->get('contextid'))),
+            'title' => ($title !== '') ? $title : get_string('notitle', 'search'),
             'docurl' => $this->get_doc_url(),
             'content' => $this->is_set('content') ? $this->format_text($this->get('content')) : null,
             'contexturl' => $this->get_context_url(),
index 20c1f3e..43137ff 100644 (file)
@@ -72,6 +72,41 @@ class document extends \core_search\document {
      * @return int
      */
     protected function get_text_format() {
-        return FORMAT_MARKDOWN;
+        return FORMAT_HTML;
+    }
+
+    /**
+     * Formats a text string coming from the search engine.
+     *
+     * @param  string $text Text to format
+     * @return string HTML text to be renderer
+     */
+    protected function format_text($text) {
+        // Since we allow output for highlighting, we need to encode html entities.
+        // This ensures plaintext html chars don't become valid html.
+        $out = s($text);
+
+        $startcount = 0;
+        $endcount = 0;
+
+        // Remove end/start pairs that span a few common seperation characters. Allows us to highlight phrases instead of words.
+        $regex = '|'.engine::HIGHLIGHT_END.'([ .,-]{0,3})'.engine::HIGHLIGHT_START.'|';
+        $out = preg_replace($regex, '$1', $out);
+
+        // Now replace our start and end highlight markers.
+        $out = str_replace(engine::HIGHLIGHT_START, '<span class="highlight">', $out, $startcount);
+        $out = str_replace(engine::HIGHLIGHT_END, '</span>', $out, $endcount);
+
+        // This makes sure any highlight tags are balanced, incase truncation or the highlight text contained our markers.
+        while ($startcount > $endcount) {
+            $out .= '</span>';
+            $endcount++;
+        }
+        while ($startcount < $endcount) {
+            $out = '<span class="highlight">' . $out;
+            $endcount++;
+        }
+
+        return parent::format_text($out);
     }
 }
index 7c480c4..5d43c57 100644 (file)
@@ -46,9 +46,19 @@ class engine extends \core_search\engine {
     const AUTOCOMMIT_WITHIN = 15000;
 
     /**
-     * @var int Highlighting fragsize.
+     * Highlighting fragsize. Slightly larger than output size (500) to allow for ... appending.
      */
-    const FRAG_SIZE = 500;
+    const FRAG_SIZE = 510;
+
+    /**
+     * Marker for the start of a highlight.
+     */
+    const HIGHLIGHT_START = '@@HI_S@@';
+
+    /**
+     * Marker for the end of a highlight.
+     */
+    const HIGHLIGHT_END = '@@HI_E@@';
 
     /**
      * @var \SolrClient
@@ -63,7 +73,7 @@ class engine extends \core_search\engine {
     /**
      * @var array Fields that can be highlighted.
      */
-    protected $highlightfields = array('content', 'description1', 'description2');
+    protected $highlightfields = array('title', 'content', 'description1', 'description2');
 
     /**
      * Prepares a Solr query, applies filters and executes it returning its results.
@@ -166,8 +176,9 @@ class engine extends \core_search\engine {
             $query->addHighlightField($field);
         }
         $query->setHighlightFragsize(static::FRAG_SIZE);
-        $query->setHighlightSimplePre('__');
-        $query->setHighlightSimplePost('__');
+        $query->setHighlightSimplePre(self::HIGHLIGHT_START);
+        $query->setHighlightSimplePost(self::HIGHLIGHT_END);
+        $query->setHighlightMergeContiguous(true);
 
         $query->setQuery($q);
 
index c68268f..63dfdd2 100644 (file)
@@ -162,7 +162,7 @@ class schema {
             $params = array(
                 'add-field' => array(
                     'name' => $fieldname,
-                    'type' => $data['type'],
+                    'type' => ($data['type'] === 'text' ? 'text_general' : $data['type']),
                     'stored' => $data['stored'],
                     'multiValued' => false,
                     'indexed' => $data['indexed']
@@ -228,7 +228,8 @@ class schema {
                         throw new \moodle_exception('errorcreatingschema', 'search_solr', '',
                             get_string('schemafieldautocreated', 'search_solr', $fieldname));
 
-                    } else if ($results->field->type !== $data['type'] ||
+                    } else if (($results->field->type !== $data['type'] &&
+                                ($data['type'] !== 'text' || $results->field->type !== 'text_general')) ||
                                 $results->field->multiValued !== false ||
                                 $results->field->indexed !== $data['indexed'] ||
                                 $results->field->stored !== $data['stored']) {
index 8c17cd7..13e7ebf 100644 (file)
@@ -275,4 +275,27 @@ class search_solr_engine_testcase extends advanced_testcase {
         $this->assertEquals(0, $results[0]->get('owneruserid'));
         $this->assertEquals($originalid, $results[0]->get('id'));
     }
+
+    public function test_highlight() {
+        global $PAGE;
+
+        $this->search->index();
+
+        $querydata = new stdClass();
+        $querydata->q = 'message';
+
+        $results = $this->search->search($querydata);
+        $this->assertCount(2, $results);
+
+        $result = reset($results);
+
+        $regex = '|'.\search_solr\engine::HIGHLIGHT_START.'message'.\search_solr\engine::HIGHLIGHT_END.'|';
+        $this->assertRegExp($regex, $result->get('content'));
+
+        $searchrenderer = $PAGE->get_renderer('core_search');
+        $exported = $result->export_for_template($searchrenderer);
+
+        $regex = '|<span class="highlight">message</span>|';
+        $this->assertRegExp($regex, $exported['content']);
+    }
 }
index 950d21a..fd11ab5 100644 (file)
@@ -56,7 +56,7 @@
 }}
 <div class="result">
     <h4 class="result-title">
-        <a href="{{{docurl}}}">{{title}}</a>
+        <a href="{{{docurl}}}">{{{title}}}</a>
     </h4>
     {{#content}}
         <div class="result-content">{{{content}}}</div>
index ee99c27..a063ea3 100644 (file)
@@ -685,11 +685,13 @@ function user_convert_text_to_menu_items($text, $page) {
             if (clean_param($namebits[0], PARAM_STRINGID) !== '') {
                 // Treat this as a language string.
                 $child->title = get_string($namebits[0], $namebits[1]);
+                $child->titleidentifier = implode(',', $namebits);
             }
         }
         if (empty($child->title)) {
             // Use it as is, don't even clean it.
             $child->title = $bits[0];
+            $child->titleidentifier = str_replace(" ", "-", $bits[0]);
         }
 
         // URL processing.
@@ -839,6 +841,7 @@ function user_get_user_navigation_info($user, $page, $options = array()) {
     $myhome->itemtype = 'link';
     $myhome->url = new moodle_url('/my/');
     $myhome->title = get_string('mymoodle', 'admin');
+    $myhome->titleidentifier = 'mymoodle,admin';
     $myhome->pix = "i/course";
     $returnobject->navitems[] = $myhome;
 
@@ -847,6 +850,7 @@ function user_get_user_navigation_info($user, $page, $options = array()) {
     $myprofile->itemtype = 'link';
     $myprofile->url = new moodle_url('/user/profile.php', array('id' => $user->id));
     $myprofile->title = get_string('profile');
+    $myprofile->titleidentifier = 'profile,moodle';
     $myprofile->pix = "i/user";
     $returnobject->navitems[] = $myprofile;
 
@@ -867,6 +871,7 @@ function user_get_user_navigation_info($user, $page, $options = array()) {
             ));
             $rolereturn->pix = "a/logout";
             $rolereturn->title = get_string('switchrolereturn');
+            $rolereturn->titleidentifier = 'switchrolereturn,moodle';
             $lastobj = $rolereturn;
 
             $returnobject->metadata['asotherrole'] = true;
@@ -897,6 +902,7 @@ function user_get_user_navigation_info($user, $page, $options = array()) {
         ));
         $userrevert->pix = "a/logout";
         $userrevert->title = get_string('logout');
+        $userrevert->titleidentifier = 'logout,moodle';
         $lastobj = $userrevert;
 
         $buildlogout = false;
@@ -909,6 +915,7 @@ function user_get_user_navigation_info($user, $page, $options = array()) {
         $logout->url = new moodle_url('/login/logout.php', array('sesskey' => sesskey()));
         $logout->pix = "a/logout";
         $logout->title = get_string('logout');
+        $logout->titleidentifier = 'logout,moodle';
         $lastobj = $logout;
     }