Merge branch 'MDL-28132' of git://github.com/timhunt/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 30 Jun 2011 23:37:43 +0000 (01:37 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 30 Jun 2011 23:37:43 +0000 (01:37 +0200)
19 files changed:
admin/lib.php [new file with mode: 0644]
backup/converter/moodle1/handlerlib.php
backup/converter/moodle1/lib.php
backup/converter/moodle1/simpletest/testlib.php
backup/moodle2/restore_stepslib.php
backup/util/helper/convert_helper.class.php
blocks/edit_form.php
course/lib.php
filter/mediaplugin/lang/en/filter_mediaplugin.php
filter/mediaplugin/styles.css
lang/en/block.php
lang/en/pagetype.php
lib/evalmath/evalmath.class.php
lib/filestorage/file_types.mm
lib/form/filepicker.php
lib/simpletest/testmathslib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/numerical.php

diff --git a/admin/lib.php b/admin/lib.php
new file mode 100644 (file)
index 0000000..dde1bc5
--- /dev/null
@@ -0,0 +1,39 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains functions used by the admin pages
+ *
+ * @since 2.1
+ * @package admin
+ * @copyright 2011 Andrew Davis
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function admin_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        'admin-setting-*' => get_string('page-admin-setting-x', 'pagetype'),
+        $pagetype => get_string('page-admin-setting', 'pagetype')
+    );
+    return $array;
+}
\ No newline at end of file
index 5c15bc2..dc10857 100644 (file)
@@ -52,6 +52,8 @@ abstract class moodle1_handlers_factory {
             new moodle1_roles_definition_handler($converter),
             new moodle1_question_bank_handler($converter),
             new moodle1_scales_handler($converter),
+            new moodle1_outcomes_handler($converter),
+            new moodle1_gradebook_handler($converter),
         );
 
         $handlers = array_merge($handlers, self::get_plugin_handlers('mod', $converter));
@@ -927,10 +929,23 @@ class moodle1_course_outline_handler extends moodle1_xml_handler {
                 $this->write_xml('module', $cminfo, array('/module/id', '/module/version'));
                 $this->close_xml_writer();
 
-                // todo: write proper grades.xml and roles.xml, for now we just make
-                // sure that those files are present
+                // write grades.xml
+                $this->open_xml_writer($directory.'/grades.xml');
+                $this->xmlwriter->begin_tag('activity_gradebook');
+                $gradeitems = $this->converter->get_stash_or_default('gradebook_modgradeitem_'.$modname, $modinstanceid, array());
+                if (!empty($gradeitems)) {
+                    $this->xmlwriter->begin_tag('grade_items');
+                    foreach ($gradeitems as $gradeitem) {
+                        $this->write_xml('grade_item', $gradeitem, array('/grade_item/id'));
+                    }
+                    $this->xmlwriter->end_tag('grade_items');
+                }
+                $this->write_xml('grade_letters', array()); // no grade_letters in module context in Moodle 1.9
+                $this->xmlwriter->end_tag('activity_gradebook');
+                $this->close_xml_writer();
+
+                // todo: write proper roles.xml, for now we just make sure the file is present
                 $this->make_sure_xml_exists($directory.'/roles.xml', 'roles');
-                $this->make_sure_xml_exists($directory.'/grades.xml', 'activity_gradebook');
             }
         }
     }
@@ -1319,7 +1334,7 @@ class moodle1_scales_handler extends moodle1_handler {
     protected $fileman = null;
 
     /**
-     * Registers path that are not qtype-specific
+     * Registers paths
      */
     public function get_paths() {
         return array(
@@ -1372,6 +1387,272 @@ class moodle1_scales_handler extends moodle1_handler {
 }
 
 
+/**
+ * Handles the conversion of the outcomes
+ */
+class moodle1_outcomes_handler extends moodle1_xml_handler {
+
+    /** @var moodle1_file_manager instance used to convert images embedded into outcome descriptions */
+    protected $fileman = null;
+
+    /**
+     * Registers paths
+     */
+    public function get_paths() {
+        return array(
+            new convert_path('gradebook_grade_outcomes', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_OUTCOMES'),
+            new convert_path(
+                'gradebook_grade_outcome', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_OUTCOMES/GRADE_OUTCOME',
+                array(
+                    'addfields' => array(
+                        'descriptionformat' => FORMAT_MOODLE,
+                    ),
+                )
+            ),
+        );
+    }
+
+    /**
+     * Prepares the file manager and starts writing outcomes.xml
+     */
+    public function on_gradebook_grade_outcomes_start() {
+
+        $syscontextid  = $this->converter->get_contextid(CONTEXT_SYSTEM);
+        $this->fileman = $this->converter->get_file_manager($syscontextid, 'grade', 'outcome');
+
+        $this->open_xml_writer('outcomes.xml');
+        $this->xmlwriter->begin_tag('outcomes_definition');
+    }
+
+    /**
+     * Processes GRADE_OUTCOME tags progressively
+     */
+    public function process_gradebook_grade_outcome(array $data, array $raw) {
+        global $CFG;
+
+        // replay the upgrade step 2009110400
+        if ($CFG->texteditors !== 'textarea') {
+            $data['description']       = text_to_html($data['description'], false, false, true);
+            $data['descriptionformat'] = FORMAT_HTML;
+        }
+
+        // convert course files embedded into the outcome description field
+        $this->fileman->itemid = $data['id'];
+        $data['description'] = moodle1_converter::migrate_referenced_files($data['description'], $this->fileman);
+
+        // write the outcome data
+        $this->write_xml('outcome', $data, array('/outcome/id'));
+
+        return $data;
+    }
+
+    /**
+     * Closes outcomes.xml
+     */
+    public function on_gradebook_grade_outcomes_end() {
+        $this->xmlwriter->end_tag('outcomes_definition');
+        $this->close_xml_writer();
+    }
+}
+
+
+/**
+ * Handles the conversion of the gradebook structures in the moodle.xml file
+ */
+class moodle1_gradebook_handler extends moodle1_xml_handler {
+
+    /** @var array of (int)gradecategoryid => (int|null)parentcategoryid */
+    protected $categoryparent = array();
+
+    /**
+     * Registers paths
+     */
+    public function get_paths() {
+        return array(
+            new convert_path('gradebook', '/MOODLE_BACKUP/COURSE/GRADEBOOK'),
+            new convert_path('gradebook_grade_letter', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_LETTERS/GRADE_LETTER'),
+            new convert_path(
+                'gradebook_grade_category', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_CATEGORIES/GRADE_CATEGORY',
+                array(
+                    'addfields' => array(
+                        'hidden' => 0,  // upgrade step 2010011200
+                    ),
+                )
+            ),
+            new convert_path('gradebook_grade_item', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_ITEMS/GRADE_ITEM'),
+            new convert_path('gradebook_grade_item_grades', '/MOODLE_BACKUP/COURSE/GRADEBOOK/GRADE_ITEMS/GRADE_ITEM/GRADE_GRADES'),
+        );
+    }
+
+    /**
+     * Initializes the in-memory structures
+     *
+     * This should not be needed actually as the moodle.xml contains just one GRADEBOOK
+     * element. But who knows - maybe someone will want to write a mass conversion
+     * tool in the future (not me definitely ;-)
+     */
+    public function on_gradebook_start() {
+        $this->categoryparent = array();
+    }
+
+    /**
+     * Processes one GRADE_LETTER data
+     *
+     * In Moodle 1.9, all grade_letters are from course context only. Therefore
+     * we put them here.
+     */
+    public function process_gradebook_grade_letter(array $data, array $raw) {
+        $this->converter->set_stash('gradebook_gradeletter', $data, $data['id']);
+    }
+
+    /**
+     * Processes one GRADE_CATEGORY data
+     */
+    public function process_gradebook_grade_category(array $data, array $raw) {
+        $this->categoryparent[$data['id']] = $data['parent'];
+        $this->converter->set_stash('gradebook_gradecategory', $data, $data['id']);
+    }
+
+    /**
+     * Processes one GRADE_ITEM data
+     */
+    public function process_gradebook_grade_item(array $data, array $raw) {
+
+        // here we use get_nextid() to get a nondecreasing sequence
+        $data['sortorder'] = $this->converter->get_nextid();
+
+        if ($data['itemtype'] === 'mod') {
+            return $this->process_mod_grade_item($data, $raw);
+
+        } else if (in_array($data['itemtype'], array('manual', 'course', 'category'))) {
+            return $this->process_nonmod_grade_item($data, $raw);
+
+        } else {
+            $this->log('unsupported grade_item type', backup::LOG_ERROR, $data['itemtype']);
+        }
+    }
+
+    /**
+     * Processes one GRADE_ITEM of the type 'mod'
+     */
+    protected function process_mod_grade_item(array $data, array $raw) {
+
+        $stashname   = 'gradebook_modgradeitem_'.$data['itemmodule'];
+        $stashitemid = $data['iteminstance'];
+        $gradeitems  = $this->converter->get_stash_or_default($stashname, $stashitemid, array());
+
+        // typically there will be single item with itemnumber 0
+        $gradeitems[$data['itemnumber']] = $data;
+
+        $this->converter->set_stash($stashname, $gradeitems, $stashitemid);
+
+        return $data;
+    }
+
+    /**
+     * Processes one GRADE_ITEM of te type 'manual' or 'course' or 'category'
+     */
+    protected function process_nonmod_grade_item(array $data, array $raw) {
+
+        $stashname   = 'gradebook_nonmodgradeitem';
+        $stashitemid = $data['id'];
+        $this->converter->set_stash($stashname, $data, $stashitemid);
+
+        return $data;
+    }
+
+    /**
+     * @todo
+     */
+    public function on_gradebook_grade_item_grades_start() {
+    }
+
+    /**
+     * Writes the collected information into gradebook.xml
+     */
+    public function on_gradebook_end() {
+
+        $this->open_xml_writer('gradebook.xml');
+        $this->xmlwriter->begin_tag('gradebook');
+        $this->write_grade_categories();
+        $this->write_grade_items();
+        $this->write_grade_letters();
+        $this->xmlwriter->end_tag('gradebook');
+        $this->close_xml_writer();
+    }
+
+    /**
+     * Writes grade_categories
+     */
+    protected function write_grade_categories() {
+
+        $this->xmlwriter->begin_tag('grade_categories');
+        foreach ($this->converter->get_stash_itemids('gradebook_gradecategory') as $gradecategoryid) {
+            $gradecategory = $this->converter->get_stash('gradebook_gradecategory', $gradecategoryid);
+            $path = $this->calculate_category_path($gradecategoryid);
+            $gradecategory['depth'] = count($path);
+            $gradecategory['path']  = '/'.implode('/', $path).'/';
+            $this->write_xml('grade_category', $gradecategory, array('/grade_category/id'));
+        }
+        $this->xmlwriter->end_tag('grade_categories');
+    }
+
+    /**
+     * Calculates the path to the grade_category
+     *
+     * Moodle 1.9 backup does not store the grade_category's depth and path. This method is used
+     * to repopulate this information using the $this->categoryparent values.
+     *
+     * @param int $categoryid
+     * @return array of ids including the categoryid
+     */
+    protected function calculate_category_path($categoryid) {
+
+        if (!array_key_exists($categoryid, $this->categoryparent)) {
+            throw new moodle1_convert_exception('gradebook_unknown_categoryid', null, $categoryid);
+        }
+
+        $path = array($categoryid);
+        $parent = $this->categoryparent[$categoryid];
+        while (!is_null($parent)) {
+            array_unshift($path, $parent);
+            $parent = $this->categoryparent[$parent];
+            if (in_array($parent, $path)) {
+                throw new moodle1_convert_exception('circular_reference_in_categories_tree');
+            }
+        }
+
+        return $path;
+    }
+
+    /**
+     * Writes grade_items
+     */
+    protected function write_grade_items() {
+
+        $this->xmlwriter->begin_tag('grade_items');
+        foreach ($this->converter->get_stash_itemids('gradebook_nonmodgradeitem') as $gradeitemid) {
+            $gradeitem = $this->converter->get_stash('gradebook_nonmodgradeitem', $gradeitemid);
+            $this->write_xml('grade_item', $gradeitem, array('/grade_item/id'));
+        }
+        $this->xmlwriter->end_tag('grade_items');
+    }
+
+    /**
+     * Writes grade_letters
+     */
+    protected function write_grade_letters() {
+
+        $this->xmlwriter->begin_tag('grade_letters');
+        foreach ($this->converter->get_stash_itemids('gradebook_gradeletter') as $gradeletterid) {
+            $gradeletter = $this->converter->get_stash('gradebook_gradeletter', $gradeletterid);
+            $this->write_xml('grade_letter', $gradeletter, array('/grade_letter/id'));
+        }
+        $this->xmlwriter->end_tag('grade_letters');
+    }
+}
+
+
 /**
  * Shared base class for activity modules, blocks and qtype handlers
  */
index dcee200..aef888e 100644 (file)
@@ -470,6 +470,22 @@ class moodle1_converter extends base_converter {
         }
     }
 
+    /**
+     * Restores a given stash or returns the given default if there is no such stash
+     *
+     * @param string $stashname name of the stash
+     * @param int $itemid optional id for multiple infos within the same stashname
+     * @param mixed $default information to return if the info has not been stashed previously
+     * @return mixed stashed data or the default value
+     */
+    public function get_stash_or_default($stashname, $itemid = 0, $default = null) {
+        try {
+            return $this->get_stash($stashname, $itemid);
+        } catch (moodle1_convert_empty_storage_exception $e) {
+            return $default;
+        }
+    }
+
     /**
      * Returns the list of existing stashes
      *
index 44634e9..addc174 100644 (file)
@@ -160,6 +160,38 @@ class moodle1_converter_test extends UnitTestCase {
         $converter->drop_stash_storage();
     }
 
+   public function test_get_stash_or_default() {
+        $converter = convert_factory::get_converter('moodle1', $this->tempdir);
+        $converter->create_stash_storage();
+
+        $this->assertTrue(is_null($converter->get_stash_or_default('stashname')));
+        $this->assertTrue(is_null($converter->get_stash_or_default('stashname', 7)));
+        $this->assertTrue('default' === $converter->get_stash_or_default('stashname', 0, 'default'));
+        $this->assertTrue(array('foo', 'bar') === $converter->get_stash_or_default('stashname', 42, array('foo', 'bar')));
+
+        //$converter->set_stash('stashname', 0);
+        //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
+
+        //$converter->set_stash('stashname', '');
+        //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
+
+        //$converter->set_stash('stashname', array());
+        //$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
+
+        $converter->set_stash('stashname', 42);
+        $this->assertTrue(42 === $converter->get_stash_or_default('stashname'));
+        $this->assertTrue(is_null($converter->get_stash_or_default('stashname', 1)));
+        $this->assertTrue(42 === $converter->get_stash_or_default('stashname', 0, 61));
+
+        $converter->set_stash('stashname', array(42 => (object)array('id' => 42)), 18);
+        $stashed = $converter->get_stash_or_default('stashname', 18, 1984);
+        $this->assertIsA($stashed, 'array');
+        $this->assertTrue(is_object($stashed[42]));
+        $this->assertTrue($stashed[42]->id === 42);
+
+        $converter->drop_stash_storage();
+    }
+
     public function test_get_contextid() {
         $converter = convert_factory::get_converter('moodle1', $this->tempdir);
 
index 26f33c0..967617d 100644 (file)
@@ -146,12 +146,18 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
         $data->courseid = $this->get_courseid();
 
-        //manual grade items store category id in categoryid
         if ($data->itemtype=='manual') {
+            // manual grade items store category id in categoryid
             $data->categoryid = $this->get_mappingid('grade_category', $data->categoryid, NULL);
-        } //course and category grade items store their category id in iteminstance
-        else if ($data->itemtype=='course' || $data->itemtype=='category') {
+        } else if ($data->itemtype=='course') {
+            // course grade item stores their category id in iteminstance
+            $coursecat = grade_category::fetch_course_category($this->get_courseid());
+            $data->iteminstance = $coursecat->id;
+        } else if ($data->itemtype=='category') {
+            // category grade items store their category id in iteminstance
             $data->iteminstance = $this->get_mappingid('grade_category', $data->iteminstance, NULL);
+        } else {
+            throw new restore_step_exception('unexpected_grade_item_type', $data->itemtype);
         }
 
         $data->scaleid   = $this->get_mappingid('scale', $data->scaleid, NULL);
@@ -300,12 +306,16 @@ class restore_gradebook_structure_step extends restore_structure_step {
 
                 //if this is an activity grade item that needs to be put back in its correct category
                 if (!empty($grade_item_backup->parentitemid)) {
-                    $updateobj->categoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid);
+                    $oldcategoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid, null);
+                    if (!is_null($oldcategoryid)) {
+                        $updateobj->categoryid = $oldcategoryid;
+                        $DB->update_record('grade_items', $updateobj);
+                    }
                 } else {
                     //mark course and category items as needing to be recalculated
                     $updateobj->needsupdate=1;
+                    $DB->update_record('grade_items', $updateobj);
                 }
-                $DB->update_record('grade_items', $updateobj);
             }
         }
         $rs->close();
@@ -2191,6 +2201,7 @@ class restore_module_structure_step extends restore_structure_step {
  *  - Activity includes completion info (file_exists)
  */
 class restore_userscompletion_structure_step extends restore_structure_step {
+    private $done = array();
 
     /**
      * To conditionally decide if this step must be executed
@@ -2235,7 +2246,33 @@ class restore_userscompletion_structure_step extends restore_structure_step {
         $data->userid = $this->get_mappingid('user', $data->userid);
         $data->timemodified = $this->apply_date_offset($data->timemodified);
 
-        $DB->insert_record('course_modules_completion', $data);
+        // Check we didn't already insert one for this cmid and userid
+        // (there aren't supposed to be duplicates in that field, but
+        // it was possible until MDL-28021 was fixed).
+        $key = $data->coursemoduleid . ',' . $data->userid;
+        if (array_key_exists($key, $this->done)) {
+            // Find the existing record
+            $existing = $DB->get_record('course_modules_completion', array(
+                    'coursemoduleid' => $data->coursemoduleid,
+                    'userid' => $data->userid), 'id, timemodified');
+            // Update it to these new values, but only if the time is newer
+            if ($existing->timemodified < $data->timemodified) {
+                $data->id = $existing->id;
+                $DB->update_record('course_modules_completion', $data);
+            }
+        } else {
+            // Normal entry where it doesn't exist already
+            $DB->insert_record('course_modules_completion', $data);
+            // Remember this entry
+            $this->done[$key] = true;
+        }
+    }
+
+    protected function after_execute() {
+        // This gets called once per activity (according to my testing).
+        // Clearing the array isn't strictly required, but avoids using
+        // unnecessary memory.
+        $this->done = array();
     }
 }
 
index 7301b4b..539f4f8 100644 (file)
@@ -89,7 +89,7 @@ abstract class convert_helper {
         $filepath   = $dirpath . '/moodle_backup.xml';
 
         if (!is_dir($dirpath)) {
-            throw new converter_helper_exception('tmp_backup_directory_not_found', $dirpath);
+            throw new convert_helper_exception('tmp_backup_directory_not_found', $dirpath);
         }
 
         if (!file_exists($filepath)) {
index 3e5a9e0..c528093 100644 (file)
@@ -99,8 +99,9 @@ class block_edit_form extends moodleform {
         $contextoptions = array();
         if ( ($parentcontext->contextlevel == CONTEXT_COURSE && $parentcontext->instanceid == SITEID) ||
             ($parentcontext->contextlevel == CONTEXT_SYSTEM)) {        // Home page
-            if ($bits[0] == 'tag') {
-                // tag always use system context, the contexts options don't make differences, so we use
+            if ($bits[0] == 'tag' || ($bits[0] == 'admin' && $bits[1] == 'setting')) {
+                // tag and admin settings always use system context
+                // the contexts options don't make differences, so we use
                 // page type patterns only
                 $mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_ENTIRE_SITE);
             } else {
@@ -125,6 +126,7 @@ class block_edit_form extends moodleform {
             $mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
         }
 
+        $displaypagetypewarning = false;
         if ($this->page->pagetype == 'site-index') {   // No need for pagetype list on home page
             $pagetypelist = array('*'=>get_string('page-x', 'pagetype'));
         } else {
@@ -134,13 +136,25 @@ class block_edit_form extends moodleform {
                 // Pushing block's existing page type pattern
                 $pagetypestringname = 'page-'.str_replace('*', 'x', $this->block->instance->pagetypepattern);
                 if (get_string_manager()->string_exists($pagetypestringname, 'pagetype')) {
-                    $pagetyelist[$this->block->instance->pagetypepattern] = get_string($pagetypestringname, 'pagetype');
+                    $pagetypelist[$this->block->instance->pagetypepattern] = get_string($pagetypestringname, 'pagetype');
+                } else {
+                    //as a last resort we could put the page type pattern in the select box
+                    //however this causes mod-data-view to be added if the only option available is mod-data-*
+
+                    //as a last resort we could put the page type pattern in the select box
+                    //however this causes mod-data-view to be added if the only option available is mod-data-*
+                    // so we are just showing a warning to users about their prev setting being reset
+                    $displaypagetypewarning = true;
                 }
             }
         }
 
         // hide page type pattern select box if there is only one choice
         if (count($pagetypelist) > 1) {
+            if ($displaypagetypewarning) {
+                $mform->addElement('static', 'pagetypewarning', '', get_string('pagetypewarning','block'));
+            }
+
             $mform->addElement('select', 'bui_pagetypepattern', get_string('restrictpagetypes', 'block'), $pagetypelist);
         } else {
             $value = array_pop(array_keys($pagetypelist));
index 8517148..5e388ad 100644 (file)
@@ -4226,8 +4226,7 @@ function course_page_type_list($pagetype, $parentcontext, $currentcontext) {
     } else {
         return array('*'=>get_string('page-x', 'pagetype'),
             'course-*'=>get_string('page-course-x', 'pagetype'),
-            'course-view-*'=>get_string('page-course-view-x', 'pagetype'),
-            'mod-*'=>get_string('page-mod-x', 'pagetype')
+            'course-view-*'=>get_string('page-course-view-x', 'pagetype')
         );
     }
 }
\ No newline at end of file
index 5729301..de7e98e 100644 (file)
@@ -30,11 +30,11 @@ $string['flashanimation_help'] = 'Files with extension *.swf. For security reaso
 $string['flashvideo'] = 'Flash video';
 $string['flashvideo_help'] = 'Files with extension *.flv and *.f4v. Plays video clips using Flowplayer, requires Flash plugin and javascript. Uses HTML 5 video fallback if multiple sources psecified.';
 $string['html5audio'] = 'HTML 5 audio';
-$string['html5audio_help'] = 'Audio files with extension *.ogg, *.acc and others. It is compatible with latest web browsers only, unfortunately there is no format that is supported by all browsers.
-Workaround is to specify fallbacks separated with # (ex: http://example.org/audio.acc#http://example.org/audio.acc#http://example.org/audio.mp3#), QuickTime player is used as a fallback for old browsers, fallback can be any audio type.';
+$string['html5audio_help'] = 'Audio files with extension *.ogg, *.aac and others. It is compatible with latest web browsers only, unfortunately there is no format that is supported by all browsers.
+Workaround is to specify fallbacks separated with # (ex: http://example.org/audio.aac#http://example.org/audio.aac#http://example.org/audio.mp3#), QuickTime player is used as a fallback for old browsers, fallback can be any audio type.';
 $string['html5video'] = 'HTML 5 video';
 $string['html5video_help'] = 'Video files with extension *.webm, *.m4v, *.ogv, *.mp4 and others. It is compatible with latest web browsers only, unfortunately there is no format that is supported by all browsers.
-Workaround is to specify fallbacks sources separated with # (ex: http://example.org/video.m4v#http://example.org/video.acc#http://example.org/video.ogv#d=640x480), QuickTime player is used as a fallback for old browsers.';
+Workaround is to specify fallbacks sources separated with # (ex: http://example.org/video.m4v#http://example.org/video.aac#http://example.org/video.ogv#d=640x480), QuickTime player is used as a fallback for old browsers.';
 $string['mp3audio'] = 'MP3 audio';
 $string['mp3audio_help'] = 'Files with extension *.mp3. Plays audio using Flowplayer, requires Flash plugin.';
 $string['legacyquicktime'] = 'QuickTime player';
index 7048fdf..bb39c83 100644 (file)
@@ -1,7 +1,7 @@
 /**
  * Filters
  */
-.mediaplugin_html5video, .mediaplugin_swf, .mediaplugin_flv, .mediaplugin_real, .mediaplugin_youtube, .mediaplugin_vimeo, .mediaplugin_wmp, .mediaplugin_qt
+.mediaplugin_html5audio, .mediaplugin_html5video, .mediaplugin_swf, .mediaplugin_flv, .mediaplugin_real, .mediaplugin_youtube, .mediaplugin_vimeo, .mediaplugin_wmp, .mediaplugin_qt
     {display:block;margin-top:5px;margin-bottom:5px;text-align: center;}
 .mediaplugin.mediaplugin_mp3 object {display:inline;height:15px;width:180px;margin-left:0.5em;}
 
index 65b4fce..c0b8f01 100644 (file)
@@ -41,6 +41,7 @@ $string['moveblockhere'] = 'Move block here';
 $string['movingthisblockcancel'] = 'Moving this block ({$a})';
 $string['onthispage'] = 'On this page';
 $string['pagetypes'] = 'Page types';
+$string['pagetypewarning'] = 'The previously specified page type is no longer selectable. Please choose the most appropriate page type below.';
 $string['region'] = 'Region';
 $string['showoncontextandsubs'] = 'Display on \'{$a}\' and any pages within it';
 $string['showoncontextonly'] = 'Display on \'{$a}\' only';
index 7a073f4..13d4325 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Strings for component 'pagetype', language 'en', branch 'MOODLE_20_STABLE'
+ * Strings for component 'pagetype', language 'en'
  *
  * @package   pagetype
  * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+$string['page-admin-setting'] = 'The current admin setting page';
+$string['page-admin-setting-x'] = 'Any admin setting page';
 $string['page-course-view-x'] = 'Any type of course main page';
 $string['page-course-x'] = 'Any course page';
 $string['page-course-report-x'] = 'Any course report';
index 0597f18..aa5539f 100644 (file)
@@ -135,7 +135,7 @@ class EvalMath {
         if (substr($expr, -1, 1) == ';') $expr = substr($expr, 0, strlen($expr)-1); // strip semicolons at the end
         //===============
         // is it a variable assignment?
-        if (preg_match('/^\s*([a-z][a-z0-9]*)\s*=\s*(.+)$/', $expr, $matches)) {
+        if (preg_match('/^\s*('.self::$namepat.')\s*=\s*(.+)$/', $expr, $matches)) {
             if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
                 return $this->trigger(get_string('cannotassigntoconstant', 'mathslib', $matches[1]));
             }
@@ -144,7 +144,7 @@ class EvalMath {
             return $this->v[$matches[1]]; // and return the resulting value
         //===============
         // is it a function assignment?
-        } elseif (preg_match('/^\s*([a-z][a-z0-9]*)\s*\(\s*([a-z][a-z0-9]*(?:\s*,\s*[a-z][a-z0-9]*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
+        } elseif (preg_match('/^\s*('.self::$namepat.')\s*\(\s*('.self::$namepat.'(?:\s*,\s*'.self::$namepat.')*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
             $fnn = $matches[1]; // get the function name
             if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
                 return $this->trigger(get_string('cannotredefinebuiltinfunction', 'mathslib', $matches[1]));
@@ -153,7 +153,7 @@ class EvalMath {
             if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
             for ($i = 0; $i<count($stack); $i++) { // freeze the state of the non-argument variables
                 $token = $stack[$i];
-                if (preg_match('/^[a-z][a-z0-9]*$/', $token) and !in_array($token, $args)) {
+                if (preg_match('/^'.self::$namepat.'$/', $token) and !in_array($token, $args)) {
                     if (array_key_exists($token, $this->v)) {
                         $stack[$i] = $this->v[$token];
                     } else {
@@ -212,7 +212,7 @@ class EvalMath {
         while(1) { // 1 Infinite Loop ;)
             $op = substr($expr, $index, 1); // get the first character at the current index
             // find out if we're currently at the beginning of a number/variable/function/parenthesis/operand
-            $ex = preg_match('/^([a-z][a-z0-9]*\(?|\d+(?:\.\d*)?|\.\d+|\()/', substr($expr, $index), $match);
+            $ex = preg_match('/^('.self::$namepat.'\(?|\d+(?:\.\d*)?(?:(e[+-]?)\d*)?|\.\d+|\()/', substr($expr, $index), $match);
             //===============
             if ($op == '-' and !$expecting_op) { // is it a negation instead of a minus?
                 $stack->push('_'); // put a negation on the stack
@@ -243,7 +243,7 @@ class EvalMath {
                     if (is_null($o2)) return $this->trigger(get_string('unexpectedclosingbracket', 'mathslib'));
                     else $output[] = $o2;
                 }
-                if (preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(2), $matches)) { // did we just close a function?
+                if (preg_match('/^('.self::$namepat.')\($/', $stack->last(2), $matches)) { // did we just close a function?
                     $fnn = $matches[1]; // get the function name
                     $arg_count = $stack->pop(); // see how many arguments there were (cleverly stored on the stack, thank you)
                     $fn = $stack->pop();
@@ -283,7 +283,7 @@ class EvalMath {
                     else $output[] = $o2; // pop the argument expression stuff and push onto the output
                 }
                 // make sure there was a function
-                if (!preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(2), $matches))
+                if (!preg_match('/^('.self::$namepat.')\($/', $stack->last(2), $matches))
                     return $this->trigger(get_string('unexpectedcomma', 'mathslib'));
                 $stack->push($stack->pop()+1); // increment the argument count
                 $stack->push('('); // put the ( back on, we'll need to pop back to it again
@@ -298,7 +298,7 @@ class EvalMath {
             } elseif ($ex and !$expecting_op) { // do we now have a function/variable/number?
                 $expecting_op = true;
                 $val = $match[1];
-                if (preg_match("/^([a-z][a-z0-9]*)\($/", $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
+                if (preg_match('/^('.self::$namepat.')\($/', $val, $matches)) { // may be func, or variable w/ implicit multiplication against parentheses...
                     if (in_array($matches[1], $this->fb) or array_key_exists($matches[1], $this->f) or array_key_exists($matches[1], $this->fc)) { // it's a func
                         $stack->push($val);
                         $stack->push(1);
@@ -316,7 +316,7 @@ class EvalMath {
             } elseif ($op == ')') {
                 //it could be only custom function with no params or general error
                 if ($stack->last() != '(' or $stack->last(2) != 1) return $this->trigger(get_string('unexpectedclosingbracket', 'mathslib'));
-                if (preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(3), $matches)) { // did we just close a function?
+                if (preg_match('/^('.self::$namepat.')\($/', $stack->last(3), $matches)) { // did we just close a function?
                     $stack->pop();// (
                     $stack->pop();// 1
                     $fn = $stack->pop();
@@ -383,8 +383,7 @@ class EvalMath {
                     for ($i = $count-1; $i >= 0; $i--) {
                         if (is_null($args[] = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
-                    $classname = 'EvalMathCalcEmul_'.$fnn;
-                    $res = call_user_func(array($classname, 'calculate'), $args);
+                    $res = call_user_func_array(array('EvalMathFuncs', $fnn), array_reverse($args));
                     if ($res === FALSE) {
                         return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
@@ -473,16 +472,15 @@ class EvalMathStack {
 
 
 // spreadsheet functions emulation
-// watch out for reversed args!!
-class EvalMathCalcEmul_average {
+class EvalMathFuncs {
 
-    static function calculate($args) {
-        return (EvalMathCalcEmul_sum::calculate($args)/count($args));
+    static function average() {
+        $args = func_get_args();
+        return (call_user_func_array(array('self', 'sum'), $args) / count($args));
     }
-}
 
-class EvalMathCalcEmul_max  {
-    static function calculate($args) {
+    static function max() {
+        $args = func_get_args();
         $res = array_pop($args);
         foreach($args as $a) {
             if ($res < $a) {
@@ -491,10 +489,9 @@ class EvalMathCalcEmul_max  {
         }
         return $res;
     }
-}
 
-class EvalMathCalcEmul_min  {
-    static function calculate($args) {
+    static function min() {
+        $args = func_get_args();
         $res = array_pop($args);
         foreach($args as $a) {
             if ($res > $a) {
@@ -503,42 +500,32 @@ class EvalMathCalcEmul_min  {
         }
         return $res;
     }
-}
-class EvalMathCalcEmul_mod {
-    static function calculate($args) {
-        return $args[1] % $args[0];
+
+    static function mod($op1, $op2) {
+        return $op1 % $op2;
     }
-}
-class EvalMathCalcEmul_pi {
-    static function calculate($args) {
+
+    static function pi() {
         return pi();
     }
-}
-class EvalMathCalcEmul_power {
-    static function calculate($args) {
-        return $args[1]^$args[0];
+
+    static function power($op1, $op2) {
+        return pow($op1, $op2);
     }
-}
 
-class EvalMathCalcEmul_round {
-    static function calculate($args) {
-        if (count($args)==1) {
-            return round($args[0]);
-        } else {
-            return round($args[1], $args[0]);
-        }
+    static function round($val, $precision = 0) {
+        return round($val, $precision);
     }
-}
-class EvalMathCalcEmul_sum {
-    static function calculate($args) {
+
+    static function sum() {
+        $args = func_get_args();
         $res = 0;
         foreach($args as $a) {
            $res += $a;
         }
         return $res;
     }
-}
-class EvalMathCalcEmul_randomised {
+
     protected static $randomseed = null;
 
     static function set_random_seed($randomseed) {
@@ -553,12 +540,7 @@ class EvalMathCalcEmul_randomised {
         }
     }
 
-}
-
-class EvalMathCalcEmul_rand_int extends EvalMathCalcEmul_randomised {
-    static function calculate($args){
-        $min = $args[1];
-        $max = $args[0];
+    static function rand_int($min, $max){
         if ($min >= $max) {
             return false; //error
         }
@@ -574,9 +556,8 @@ class EvalMathCalcEmul_rand_int extends EvalMathCalcEmul_randomised {
         } while (($min + $randomno) > $max);
         return $min + $randomno;
     }
-}
-class EvalMathCalcEmul_rand_float extends EvalMathCalcEmul_randomised {
-    static function calculate(){
+
+    static function rand_float(){
         $randomvalue = array_shift(unpack('v', md5(self::get_random_seed(), true)));
         return $randomvalue / 65536;
     }
index 841fce7..64a12bb 100644 (file)
@@ -19,6 +19,7 @@
 <node ID="_Freemind_Link_313976796" TEXT=".ra"/>
 <node ID="_Freemind_Link_709595453" TEXT=".wma"/>
 <node TEXT=".ogg"/>
+<node ID="ID_421461117" TEXT=".aac"/>
 </node>
 <node ID="_Freemind_Link_1800832653" TEXT="non_web_audio">
 <node ID="_Freemind_Link_1772266185" TEXT=".ape"/>
index c5af6e1..039ab76 100644 (file)
@@ -112,9 +112,13 @@ class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
     function exportValue(&$submitValues, $assoc = false) {
         global $USER;
 
+        $draftitemid = $this->_findValue($submitValues);
+        if (null === $draftitemid) {
+            $draftitemid = $this->getValue();
+        }
+
         // make sure max one file is present and it is not too big
-        if (!empty($submitValues[$this->_attributes['name']])) {
-            $draftitemid = $submitValues[$this->_attributes['name']];
+        if (!is_null($draftitemid)) {
             $fs = get_file_storage();
             $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
             if ($files = $fs->get_area_files($usercontext->id, 'user', 'draft', $draftitemid, 'id DESC', false)) {
@@ -128,10 +132,8 @@ class MoodleQuickForm_filepicker extends HTML_QuickForm_input {
                     $file->delete();
                 }
             }
-            return array($this->_attributes['name'] => $submitValues[$this->_attributes['name']]);
-        } else {
-            return null;
         }
 
+        return $this->_prepareValue($draftitemid, true);
     }
 }
index a17bd0a..f1cfb56 100644 (file)
@@ -1,7 +1,20 @@
 <?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/>.
 if (!defined('MOODLE_INTERNAL')) {
-    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
+    die('Direct access to this script is forbidden.');///  It must be included from a Moodle page
 }
 
 require_once($CFG->libdir . '/mathslib.php');
@@ -19,7 +32,7 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests the basic formula evaluation
      */
-    function test__basic() {
+    public function test__basic() {
         $formula = new calc_formula('=1+2');
         $res = $formula->evaluate();
         $this->assertEqual($res, 3, '3+1 is: %s');
@@ -28,8 +41,8 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests the formula params
      */
-    function test__params() {
-        $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30));
+    public function test__params() {
+        $formula = new calc_formula('=a+b+c', array('a'=>10, 'b'=>20, 'c'=>30));
         $res = $formula->evaluate();
         $this->assertEqual($res, 60, '10+20+30 is: %s');
     }
@@ -37,11 +50,11 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests the changed params
      */
-    function test__changing_params() {
-        $formula = new calc_formula('=a+b+c', array('a'=>10,'b'=>20,'c'=>30));
+    public function test__changing_params() {
+        $formula = new calc_formula('=a+b+c', array('a'=>10, 'b'=>20, 'c'=>30));
         $res = $formula->evaluate();
         $this->assertEqual($res, 60, '10+20+30 is: %s');
-        $formula->set_params(array('a'=>1,'b'=>2,'c'=>3));
+        $formula->set_params(array('a'=>1, 'b'=>2, 'c'=>3));
         $res = $formula->evaluate();
         $this->assertEqual($res, 6, 'changed params 1+2+3 is: %s');
     }
@@ -49,20 +62,31 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests the spreadsheet emulation function in formula
      */
-    function test__calc_function() {
-        $formula = new calc_formula('=sum(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
+    public function test__calc_function() {
+        $formula = new calc_formula('=sum(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
         $res = $formula->evaluate();
-        $this->assertEqual($res, 60, 'sum(a,b,c) is: %s');
+        $this->assertEqual($res, 60, 'sum(a, b, c) is: %s');
+    }
+
+    public function test_other_functions() {
+        $formula = new calc_formula('=average(1,2,3)');
+        $this->assertEqual($formula->evaluate(), 2);
+
+        $formula = new calc_formula('=mod(10,3)');
+        $this->assertEqual($formula->evaluate(), 1);
+
+        $formula = new calc_formula('=power(2,3)');
+        $this->assertEqual($formula->evaluate(), 8);
     }
 
     /**
      * Tests the min and max functions
      */
-    function test__minmax_function() {
-        $formula = new calc_formula('=min(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
+    public function test__minmax_function() {
+        $formula = new calc_formula('=min(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
         $res = $formula->evaluate();
         $this->assertEqual($res, 10, 'minimum is: %s');
-        $formula = new calc_formula('=max(a,b,c)', array('a'=>10,'b'=>20,'c'=>30));
+        $formula = new calc_formula('=max(a, b, c)', array('a'=>10, 'b'=>20, 'c'=>30));
         $res = $formula->evaluate();
         $this->assertEqual($res, 30, 'maximum is: %s');
     }
@@ -70,8 +94,8 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests special chars
      */
-    function test__specialchars() {
-        $formula = new calc_formula('=gi1 + gi2 + gi11', array('gi1'=>10,'gi2'=>20,'gi11'=>30));
+    public function test__specialchars() {
+        $formula = new calc_formula('=gi1 + gi2 + gi11', array('gi1'=>10, 'gi2'=>20, 'gi11'=>30));
         $res = $formula->evaluate();
         $this->assertEqual($res, 60, 'sum is: %s');
     }
@@ -79,49 +103,52 @@ class mathsslib_test extends UnitTestCase {
     /**
      * Tests some slightly more complex expressions
      */
-    function test__more_complex_expressions() {
+    public function test__more_complex_expressions() {
         $formula = new calc_formula('=pi() + a', array('a'=>10));
         $res = $formula->evaluate();
         $this->assertEqual($res, pi()+10);
         $formula = new calc_formula('=pi()^a', array('a'=>10));
         $res = $formula->evaluate();
-        $this->assertEqual($res, pow(pi(),10));
+        $this->assertEqual($res, pow(pi(), 10));
         $formula = new calc_formula('=-8*(5/2)^2*(1-sqrt(4))-8');
         $res = $formula->evaluate();
-        $this->assertEqual($res, -8*pow((5/2),2)*(1-sqrt(4))-8);
+        $this->assertEqual($res, -8*pow((5/2), 2)*(1-sqrt(4))-8);
     }
 
     /**
      * Tests some slightly more complex expressions
      */
-    function test__error_handling() {
-        if (debugging('', DEBUG_DEVELOPER)){
+    public function test__error_handling() {
+        if (debugging('', DEBUG_DEVELOPER)) {
             $this->expectError();
         }
         $formula = new calc_formula('=pi( + a', array('a'=>10));
         $res = $formula->evaluate();
         $this->assertEqual($res, false);
-        $this->assertEqual($formula->get_error(), get_string('unexpectedoperator', 'mathslib', '+'));
+        $this->assertEqual($formula->get_error(),
+                                        get_string('unexpectedoperator', 'mathslib', '+'));
 
-        if (debugging('', DEBUG_DEVELOPER)){
+        if (debugging('', DEBUG_DEVELOPER)) {
             $this->expectError();
         }
         $formula = new calc_formula('=pi(');
         $res = $formula->evaluate();
         $this->assertEqual($res, false);
-        $this->assertEqual($formula->get_error(), get_string('expectingaclosingbracket', 'mathslib'));
+        $this->assertEqual($formula->get_error(),
+                                        get_string('expectingaclosingbracket', 'mathslib'));
 
-        if (debugging('', DEBUG_DEVELOPER)){
+        if (debugging('', DEBUG_DEVELOPER)) {
             $this->expectError();
         }
         $formula = new calc_formula('=pi()^');
         $res = $formula->evaluate();
         $this->assertEqual($res, false);
-        $this->assertEqual($formula->get_error(), get_string('operatorlacksoperand', 'mathslib', '^'));
+        $this->assertEqual($formula->get_error(),
+                                        get_string('operatorlacksoperand', 'mathslib', '^'));
 
     }
 
-    function test_rounding_function() {
+    public function test_rounding_function() {
         $formula = new calc_formula('=round(2.5)');
         $this->assertEqual($formula->evaluate(), 3);
 
@@ -140,7 +167,6 @@ class mathsslib_test extends UnitTestCase {
         $formula = new calc_formula('=round(-2.5)');
         $this->assertEqual($formula->evaluate(), -3);
 
-
         $formula = new calc_formula('=ceil(2.5)');
         $this->assertEqual($formula->evaluate(), 3);
 
@@ -159,7 +185,6 @@ class mathsslib_test extends UnitTestCase {
         $formula = new calc_formula('=ceil(-2.5)');
         $this->assertEqual($formula->evaluate(), -2);
 
-
         $formula = new calc_formula('=floor(2.5)');
         $this->assertEqual($formula->evaluate(), 2);
 
@@ -180,6 +205,26 @@ class mathsslib_test extends UnitTestCase {
 
     }
 
+    public function test_scientific_notation() {
+        $formula = new calc_formula('=10e10');
+        $this->assertWithinMargin($formula->evaluate(), 1e11, 1e11*1e-15);
+
+        $formula = new calc_formula('=10e-10');
+        $this->assertWithinMargin($formula->evaluate(), 1e-9, 1e11*1e-15);
+
+        $formula = new calc_formula('=10e+10');
+        $this->assertWithinMargin($formula->evaluate(), 1e11, 1e11*1e-15);
+
+        $formula = new calc_formula('=10e10*5');
+        $this->assertWithinMargin($formula->evaluate(), 5e11, 1e11*1e-15);
+
+        $formula = new calc_formula('=10e10^2');
+        $this->assertWithinMargin($formula->evaluate(), 1e22, 1e22*1e-15);
+
+    }
+
+
+
 }
 
 
index b1c8136..c5fe160 100644 (file)
@@ -95,7 +95,12 @@ class lesson_page_type_essay extends lesson_page {
             redirect(new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$this->properties->id)));
         }
 
-        $studentanswer = $data->answer['text'];
+        if (is_array($data->answer)) {
+            $studentanswer = $data->answer['text'];
+        } else {
+            $studentanswer = $data->answer;
+        }
+
         if (trim($studentanswer) === '') {
             $result->noanswer = true;
             return $result;
@@ -261,8 +266,9 @@ class lesson_display_answer_form_essay extends moodleform {
             if (isset($USER->modattempts[$lessonid]->useranswer) && !empty($USER->modattempts[$lessonid]->useranswer)) {
                 $attrs = array('disabled' => 'disabled');
                 $hasattempt = true;
-                $useranswer = unserialize($USER->modattempts[$lessonid]->useranswer);
-                $useranswer = htmlspecialchars_decode($useranswer->answer, ENT_QUOTES);
+                $useranswertemp = unserialize($USER->modattempts[$lessonid]->useranswer);
+                $useranswer = htmlspecialchars_decode($useranswertemp->answer, ENT_QUOTES);
+                $useranswerraw = $useranswertemp->answer;
             }
         }
 
@@ -282,7 +288,7 @@ class lesson_display_answer_form_essay extends moodleform {
 
         if ($hasattempt) {
             $mform->addElement('hidden', 'answer', $useranswerraw);
-            $mform->setType('answer', PARAM_CLEANHTML);
+            $mform->setType('answer', PARAM_RAW);
             $mform->addElement('html', $OUTPUT->container(get_string('youranswer', 'lesson'), 'youranswer'));
             $mform->addElement('html', $OUTPUT->container($useranswer, 'reviewessay'));
             $this->add_action_buttons(null, get_string("nextpage", "lesson"));
index 078af89..3e666c5 100644 (file)
@@ -542,6 +542,15 @@ class lesson_display_answer_form_multichoice_multianswer extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        $useranswers = array();
+        if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+            $useranswers = explode(',', $USER->modattempts[$lessonid]->useranswer);
+        }
+
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -554,16 +563,26 @@ class lesson_display_answer_form_multichoice_multianswer extends moodleform {
 
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            // NOTE: our silly checkbox supports only value '1' - we can not use it like the radiobox above!!!!!!
-            $mform->addElement('checkbox','answer['.$answer->id.']',null,format_text($answer->answer, $answer->answerformat, $options));
-            $mform->setType('answer['.$answer->id.']', PARAM_INT);
-            if (isset($USER->modattempts[$lessonid]) && $answer->id == $attempt->answerid) {
+            $answerid = 'answer['.$answer->id.']';
+            if ($hasattempt && in_array($answer->id, $useranswers)) {
+                $answerid = 'answer_'.$answer->id;
+                $mform->addElement('hidden', 'answer['.$answer->id.']', $answer->answer);
+                $mform->setType('answer['.$answer->id.']', PARAM_TEXT);
+                $mform->setDefault($answerid, true);
                 $mform->setDefault('answer['.$answer->id.']', true);
             }
+            // NOTE: our silly checkbox supports only value '1' - we can not use it like the radiobox above!!!!!!
+            $mform->addElement('checkbox', $answerid, null, format_text($answer->answer, $answer->answerformat, $options), $disabled);
+            $mform->setType($answerid, PARAM_INT);
+
             $mform->addElement('html', '</div>');
         }
 
-        $this->add_action_buttons(null, get_string("pleasecheckoneormoreanswers", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index 18fb54f..ee5b50f 100644 (file)
@@ -50,7 +50,7 @@ class lesson_page_type_numerical extends lesson_page {
     }
     public function display($renderer, $attempt) {
         global $USER, $CFG, $PAGE;
-        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents()));
+        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents(), 'lessonid'=>$this->lesson->id));
         $data = new stdClass;
         $data->id = $PAGE->cm->id;
         $data->pageid = $this->properties->id;
@@ -268,6 +268,15 @@ class lesson_display_answer_form_numerical extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $attrs = array('size'=>'50', 'maxlength'=>'200');
+        if (isset($this->_customdata['lessonid'])) {
+            $lessonid = $this->_customdata['lessonid'];
+            if (isset($USER->modattempts[$lessonid]->useranswer)) {
+                $attrs['readonly'] = 'readonly';
+                $hasattempt = true;
+            }
+        }
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -278,10 +287,14 @@ class lesson_display_answer_form_numerical extends moodleform {
         $mform->addElement('hidden', 'pageid');
         $mform->setType('pageid', PARAM_INT);
 
-        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), array('size'=>'50', 'maxlength'=>'200'));
+        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), $attrs);
         $mform->setType('answer', PARAM_FLOAT);
 
-        $this->add_action_buttons(null, get_string("pleaseenteryouranswerinthebox", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }