Merge branch 'MDL-28133' of git://github.com/timhunt/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 30 Jun 2011 23:10:06 +0000 (01:10 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 30 Jun 2011 23:10:06 +0000 (01:10 +0200)
17 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/filestorage/file_types.mm
lib/form/filepicker.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 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 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"));
+        }
     }
 
 }