Merge branch 'wip-MDL-47398-master' of git://github.com/marinaglancy/moodle
authorSam Hemelryk <sam@moodle.com>
Mon, 29 Sep 2014 01:35:06 +0000 (14:35 +1300)
committerSam Hemelryk <sam@moodle.com>
Mon, 29 Sep 2014 01:35:06 +0000 (14:35 +1300)
52 files changed:
admin/settings/grades.php
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js
availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js
availability/yui/src/form/js/form.js
course/classes/management_renderer.php
grade/edit/tree/category_form.php
grade/edit/tree/item_form.php
grade/edit/tree/lib.php
grade/report/grader/lib.php
grade/report/grader/module.js
grade/report/grader/preferences_form.php
grade/report/grader/settings.php
grade/tests/behat/grade_UI_settings.feature [new file with mode: 0644]
lang/en/grades.php
lib/classes/plugin_manager.php
lib/classes/update/deployer.php
lib/clilib.php
lib/filelib.php
lib/grade/grade_category.php
lib/grade/grade_grade.php
lib/grade/grade_item.php
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js
lib/yui/src/notification/js/dialogue.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar-debug.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar-min.js
lib/yuilib/2in3/2.9.0/build/yui2-calendar/yui2-calendar.js
mod/assign/locallib.php
mod/assign/mod_form.php
mod/forum/discuss.php
mod/forum/lib.php
mod/forum/tests/behat/discussion_subscriptions.feature
mod/lesson/backup/moodle2/backup_lesson_stepslib.php
mod/lesson/backup/moodle2/restore_lesson_activity_task.class.php
mod/lesson/backup/moodle2/restore_lesson_stepslib.php
mod/lesson/editpage.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/tests/behat/questions_images.feature [new file with mode: 0644]
mod/lesson/tests/fixtures/moodle_logo.jpg [new file with mode: 0644]
question/format/gift/tests/behat/import.feature
question/format/webct/tests/behat/import.feature
question/format/xml/tests/behat/import.feature
theme/bootstrapbase/less/moodle/responsive.less
user/index.php
version.php

index 6d12d99..2cb6122 100644 (file)
@@ -68,6 +68,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
 
         $temp->add(new admin_setting_special_gradelimiting());
 
+        $temp->add(new admin_setting_configcheckbox('grade_report_showmin',
+                                                    get_string('minimum_show', 'grades'),
+                                                    get_string('minimum_show_help', 'grades'), '1'));
+
         $temp->add(new admin_setting_special_gradepointmax());
 
         $temp->add(new admin_setting_special_gradepointdefault());
@@ -125,6 +129,9 @@ if (has_capability('moodle/grade:manage', $systemcontext)
         $defaults['forced'] = false;
         $temp->add(new admin_setting_gradecat_combo('grade_droplow', new lang_string('droplow', 'grades'),
                     new lang_string('droplow_help', 'grades'), $defaults, $options));
+
+        $temp->add(new admin_setting_configcheckbox('grade_overridecat', new lang_string('overridecat', 'grades'),
+                   new lang_string('overridecat_help', 'grades'), 1));
     }
     $ADMIN->add('grades', $temp);
 
index b7c0509..185800c 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-debug.js differ
index 82b5c5b..9c578a0 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form-min.js differ
index b7c0509..185800c 100644 (file)
Binary files a/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js and b/availability/yui/build/moodle-core_availability-form/moodle-core_availability-form.js differ
index 5f26ced..099fe5e 100644 (file)
@@ -926,20 +926,19 @@ M.core_availability.Item.prototype.pluginNode = null;
 M.core_availability.EyeIcon = function(individual, shown) {
     this.individual = individual;
     this.span = Y.Node.create('<a class="availability-eye" href="#" role="button">');
-    var iconBase = M.cfg.wwwroot + '/theme/image.php/' + M.cfg.theme + '/core/' + M.cfg.themerev;
     var icon = Y.Node.create('<img />');
     this.span.appendChild(icon);
 
     // Set up button text and icon.
     var suffix = individual ? '_individual' : '_all';
     var setHidden = function() {
-        icon.set('src', iconBase + '/i/show');
+        icon.set('src', M.util.image_url('i/show', 'core'));
         icon.set('alt', M.str.availability['hidden' + suffix]);
         this.span.set('title', M.str.availability['hidden' + suffix] + ' \u2022 ' +
                 M.str.availability.show_verb);
     };
     var setShown = function() {
-        icon.set('src', iconBase + '/i/hide');
+        icon.set('src', M.util.image_url('i/hide', 'core'));
         icon.set('alt', M.str.availability['shown' + suffix]);
         this.span.set('title', M.str.availability['shown' + suffix] + ' \u2022 ' +
                 M.str.availability.hide_verb);
@@ -1004,9 +1003,8 @@ M.core_availability.EyeIcon.prototype.isHidden = function() {
 M.core_availability.DeleteIcon = function(toDelete) {
     this.span = Y.Node.create('<a class="availability-delete" href="#" title="' +
             M.str.moodle['delete'] + '" role="button">');
-    var img = Y.Node.create('<img src="' +
-            M.cfg.wwwroot + '/theme/image.php/' + M.cfg.theme + '/core/' + M.cfg.themerev +
-            '/t/delete" alt="' + M.str.moodle['delete'] + '" />');
+    var img = Y.Node.create('<img src="' + M.util.image_url('t/delete', 'core') +
+            '" alt="' + M.str.moodle['delete'] + '" />');
     this.span.appendChild(img);
     var click = function(e) {
         e.preventDefault();
index a36227d..c48905c 100644 (file)
@@ -1216,6 +1216,15 @@ class core_course_management_renderer extends plugin_renderer_base {
                     array('class' => 'action-edit')
                 );
             }
+            // Delete.
+            if ($course->can_delete()) {
+                $actions[] = $this->output->action_icon(
+                    new moodle_url('/course/delete.php', array('id' => $course->id)),
+                    new pix_icon('t/delete', get_string('delete')),
+                    null,
+                    array('class' => 'action-delete')
+                );
+            }
             // Show/Hide.
             if ($course->can_change_visibility()) {
                     $actions[] = $this->output->action_icon(
index 950e3bf..f893091 100644 (file)
@@ -162,11 +162,13 @@ class edit_category_form extends moodleform {
         $mform->disabledIf('grade_item_grademax', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
         $mform->disabledIf('grade_item_grademax', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
 
-        $mform->addElement('text', 'grade_item_grademin', get_string('grademin', 'grades'));
-        $mform->setType('grade_item_grademin', PARAM_RAW);
-        $mform->addHelpButton('grade_item_grademin', 'grademin', 'grades');
-        $mform->disabledIf('grade_item_grademin', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->disabledIf('grade_item_grademin', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
+        if ((bool) get_config('moodle', 'grade_report_showmin')) {
+            $mform->addElement('text', 'grade_item_grademin', get_string('grademin', 'grades'));
+            $mform->setType('grade_item_grademin', PARAM_RAW);
+            $mform->addHelpButton('grade_item_grademin', 'grademin', 'grades');
+            $mform->disabledIf('grade_item_grademin', 'grade_item_gradetype', 'noteq', GRADE_TYPE_VALUE);
+            $mform->disabledIf('grade_item_grademin', 'aggregation', 'eq', GRADE_AGGREGATE_SUM);
+        }
 
         $mform->addElement('text', 'grade_item_gradepass', get_string('gradepass', 'grades'));
         $mform->setType('grade_item_gradepass', PARAM_RAW);
@@ -413,7 +415,9 @@ class edit_category_form extends moodleform {
             if ($grade_item->is_outcome_item()) {
                 // we have to prevent incompatible modifications of outcomes if outcomes disabled
                 $mform->removeElement('grade_item_grademax');
-                $mform->removeElement('grade_item_grademin');
+                if ($mform->elementExists('grade_item_grademin')) {
+                    $mform->removeElement('grade_item_grademin');
+                }
                 $mform->removeElement('grade_item_gradetype');
                 $mform->removeElement('grade_item_display');
                 $mform->removeElement('grade_item_decimals');
index b9dc0d2..13ad687 100644 (file)
@@ -90,10 +90,12 @@ class edit_item_form extends moodleform {
         $mform->disabledIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
         $mform->setType('grademax', PARAM_RAW);
 
-        $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
-        $mform->addHelpButton('grademin', 'grademin', 'grades');
-        $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
-        $mform->setType('grademin', PARAM_RAW);
+        if ((bool) get_config('moodle', 'grade_report_showmin')) {
+            $mform->addElement('text', 'grademin', get_string('grademin', 'grades'));
+            $mform->addHelpButton('grademin', 'grademin', 'grades');
+            $mform->disabledIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
+            $mform->setType('grademin', PARAM_RAW);
+        }
 
         $mform->addElement('text', 'gradepass', get_string('gradepass', 'grades'));
         $mform->addHelpButton('gradepass', 'gradepass', 'grades');
@@ -235,7 +237,9 @@ class edit_item_form extends moodleform {
             if ($grade_item->is_outcome_item()) {
                 // we have to prevent incompatible modifications of outcomes if outcomes disabled
                 $mform->removeElement('grademax');
-                $mform->removeElement('grademin');
+                if ($mform->elementExists('grademin')) {
+                    $mform->removeElement('grademin');
+                }
                 $mform->removeElement('gradetype');
                 $mform->removeElement('display');
                 $mform->removeElement('decimals');
@@ -244,7 +248,11 @@ class edit_item_form extends moodleform {
             } else {
                 if ($grade_item->is_external_item()) {
                     // following items are set up from modules and should not be overrided by user
-                    $mform->hardFreeze('itemname,gradetype,grademax,grademin,scaleid');
+                    if ($mform->elementExists('grademin')) {
+                        // The site setting grade_report_showmin may have prevented grademin being added to the form.
+                        $mform->hardFreeze('grademin');
+                    }
+                    $mform->hardFreeze('itemname,gradetype,grademax,scaleid');
                     if ($grade_item->itemnumber == 0) {
                         // the idnumber of grade itemnumber 0 is synced with course_modules
                         $mform->hardFreeze('idnumber');
@@ -316,7 +324,6 @@ class edit_item_form extends moodleform {
         }
     }
 
-
 /// perform extra validation before submission
     function validation($data, $files) {
         global $COURSE;
index 1315408..c483ff2 100644 (file)
@@ -49,12 +49,22 @@ class grade_edit_tree {
     public $table;
 
     public $categories = array();
+
+    /**
+     * Show calculator icons next to manual grade items
+     * @var bool $show_calculations
+     */
+    private $show_calculations;
+
     /**
      * Constructor
      */
     public function __construct($gtree, $moving=false, $gpr) {
         global $USER, $OUTPUT, $COURSE;
 
+        $systemdefault = get_config('moodle', 'grade_report_showcalculations');
+        $this->show_calculations = get_user_preferences('grade_report_showcalculations', $systemdefault);
+
         $this->gtree = $gtree;
         $this->moving = $moving;
         $this->gpr = $gpr;
@@ -138,7 +148,9 @@ class grade_edit_tree {
             $actions .= $this->gtree->get_edit_icon($element, $this->gpr);
         }
 
-        $actions .= $this->gtree->get_calculation_icon($element, $this->gpr);
+        if ($this->show_calculations) {
+            $actions .= $this->gtree->get_calculation_icon($element, $this->gpr);
+        }
 
         if ($element['type'] == 'item' or ($element['type'] == 'category' and $element['depth'] > 1)) {
             if ($this->element_deletable($element)) {
index 0c6e692..cf02a6e 100644 (file)
@@ -95,6 +95,12 @@ class grade_report_grader extends grade_report {
      */
     protected $feedback_trunc_length = 50;
 
+    /**
+     * Allow category grade overriding
+     * @var bool $overridecat
+     */
+    protected $overridecat;
+
     /**
      * Constructor. Sets local copies of user preferences and initialises grade_tree.
      * @param int $courseid
@@ -143,6 +149,8 @@ class grade_report_grader extends grade_report {
         $this->setup_groups();
         $this->setup_users();
         $this->setup_sortitemid();
+
+        $this->overridecat = (bool)get_config('moodle', 'grade_overridecat');
     }
 
     /**
@@ -1029,7 +1037,13 @@ class grade_report_grader extends grade_report {
                     }
 
                     if ($enableajax) {
-                        $itemcell->attributes['class'] .= ' clickable';
+                        $canoverride = true;
+                        if ($item->is_category_item() || $item->is_course_item()) {
+                            $canoverride = (bool) get_config('moodle', 'grade_overridecat');
+                        }
+                        if ($canoverride) {
+                            $itemcell->attributes['class'] .= ' clickable';
+                        }
                     }
 
                     if ($item->needsupdate) {
@@ -1485,7 +1499,16 @@ class grade_report_grader extends grade_report {
         // Init all icons
         $editicon = '';
 
-        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem') {
+        $editable = true;
+
+        if ($element['type'] == 'grade') {
+            $item = $element['object']->grade_item;
+            if ($item->is_course_item() or $item->is_category_item()) {
+                $editable = $this->overridecat;
+            }
+        }
+
+        if ($element['type'] != 'categoryitem' && $element['type'] != 'courseitem' && $editable) {
             $editicon = $this->gtree->get_edit_icon($element, $this->gpr);
         }
 
index f67474a..6263883 100644 (file)
@@ -314,7 +314,7 @@ M.gradereport_grader.classes.ajax = function(report, cfg) {
     this.existingfields = [];
 
     if (!report.isediting) {
-        report.table.all('.cell.grade').on('makeditable|click', this.make_editable, this);
+        report.table.all('.clickable').on('click', this.make_editable, this);
     } else {
         for (var userid in report.users) {
             if (!this.existingfields[userid]) {
@@ -1043,7 +1043,7 @@ M.gradereport_grader.classes.textfield.prototype.revert = function() {
         }
     }
     this.keyevents = [];
-    this.node.on('makeditable|click', this.report.ajax.make_editable, this.report.ajax);
+    this.node.on('click', this.report.ajax.make_editable, this.report.ajax);
 };
 /**
  * Gets the grade for current cell
index ba2cb24..241adf6 100644 (file)
@@ -55,7 +55,9 @@ class grader_report_preferences_form extends moodleform {
         if (has_capability('moodle/grade:manage', $context)) {
 
             $preferences['prefshow'] = array();
-            $preferences['prefshow']['showcalculations']  = $checkbox_default;
+
+            $preferences['prefshow']['showcalculations'] = $checkbox_default;
+
             $preferences['prefshow']['showeyecons']       = $checkbox_default;
             if ($canviewhidden) {
                 $preferences['prefshow']['showaverages']  = $checkbox_default;
index d1b02af..cb70000 100644 (file)
@@ -55,8 +55,9 @@ if ($ADMIN->fulltree) {
     $settings->add(new admin_setting_configcheckbox('grade_report_enableajax', get_string('enableajax', 'grades'),
                                                 get_string('enableajax_help', 'grades'), 0));
 
-    $settings->add(new admin_setting_configcheckbox('grade_report_showcalculations', get_string('showcalculations', 'grades'),
-                                                get_string('showcalculations_help', 'grades'), 0));
+    $settings->add(new admin_setting_configcheckbox('grade_report_showcalculations',
+                                                    get_string('showcalculations', 'grades'),
+                                                    get_string('showcalculations_help', 'grades'), 1));
 
     $settings->add(new admin_setting_configcheckbox('grade_report_showeyecons', get_string('showeyecons', 'grades'),
                                                 get_string('showeyecons_help', 'grades'), 0));
diff --git a/grade/tests/behat/grade_UI_settings.feature b/grade/tests/behat/grade_UI_settings.feature
new file mode 100644 (file)
index 0000000..0177e34
--- /dev/null
@@ -0,0 +1,58 @@
+@core @core_grades
+Feature: Site settings can be used to hide parts of the gradebook UI
+  In order to hide UI elements
+  As an admin
+  I need to modify gradebook related system settings
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category | format |
+      | Course 1 | C1 | 0 | topics |
+    And the following "users" exist:
+      | username | firstname | lastname | email | idnumber |
+      | student1 | Student | 1 | student1@asd.com | s1 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | student1 | C1 | student |
+    And the following "activities" exist:
+      | activity | course | idnumber | name | intro |
+      | assign | C1 | assign1 | Assignment1 | Assignment 1 intro |
+    And I log in as "admin"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I turn editing mode on
+
+  @javascript
+  Scenario: Hide minimum grade
+    When I click on "Edit  assign Assignment1" "link"
+    And I should see "Minimum grade"
+    Then I navigate to "General settings" node in "Site administration > Grades"
+    And I click on "Show minimum grade" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And I click on "Edit  assign Assignment1" "link"
+    And I should not see "Minimum grade"
+
+  @javascript
+  Scenario: Hide calculation icons
+    And "Edit calculation for   Course total" "link" should exist
+    When I navigate to "Grader report" node in "Site administration > Grades > Report settings"
+    And I click on "Show calculations" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    Then "Edit calculation for   Course total" "link" should not exist
+
+  @javascript
+  Scenario: Disable category overriding
+    And ".r0 .course input[type='text']" "css_element" should exist
+    Then I navigate to "Grade category settings" node in "Site administration > Grades"
+    And I click on "Allow category grades to be manually overridden" "checkbox"
+    And I press "Save changes"
+    And I follow "Home"
+    And I follow "Course 1"
+    And I follow "Grades"
+    And ".r0 .course input[type='text']" "css_element" should not exist
index dd379f8..702e278 100644 (file)
@@ -420,6 +420,8 @@ $string['meanselection'] = 'Grades selected for column averages';
 $string['meanselection_help'] = 'This setting determines whether cells with no grade should be included when calculating the average (mean) for each category or grade item.';
 $string['median'] = 'Median';
 $string['min'] = 'Lowest';
+$string['minimum_show'] = 'Show minimum grade';
+$string['minimum_show_help'] = 'Minimum grade is used in calculating grades and weights. If not shown, minimum grade will default to zero and cannot be edited.';
 $string['missingscale'] = 'Scale must be selected';
 $string['mode'] = 'Mode';
 $string['modgradeerrorbadpoint'] = 'Invalid Grade Value. This must be an integer between 0 and {$a}';
@@ -496,6 +498,8 @@ $string['outcomesstandardavailable'] = 'Available standard outcomes';
 $string['outcomestandard'] = 'Standard outcome';
 $string['outcomestandard_help'] = 'A standard outcome is available site-wide, for all courses.';
 $string['overallaverage'] = 'Overall average';
+$string['overridecat'] = 'Allow category grades to be manually overridden';
+$string['overridecat_help'] = 'Disabling this setting makes it impossible for users to override category grades.';
 $string['overridden'] = 'Overridden';
 $string['overridden_help'] = 'If ticked, the grade can no longer be changed from within the related activity.
 
@@ -603,7 +607,7 @@ $string['showallstudents'] = 'Show all Students';
 $string['showaverages'] = 'Show column averages';
 $string['showaverages_help'] = 'If enabled, the grader report will contain an additional row displaying the average (mean) for each category and grade item.';
 $string['showcalculations'] = 'Show calculations';
-$string['showcalculations_help'] = 'If enabled, when editing is turned on, a calculator icon is shown for each grade item and category, with tool tips over calculated items and a visual indicator that a column is calculated.';
+$string['showcalculations_help'] = 'If enabled, when editing, a calculator icon is shown for each grade item and category with a visual indicator that a grade item is calculated.';
 $string['showeyecons'] = 'Show show/hide icons';
 $string['showeyecons_help'] = 'If enabled, when editing is turned on, a show/hide icon is shown for each grade for controlling its visibility to the student.';
 $string['showgroups'] = 'Show groups';
@@ -683,6 +687,8 @@ $string['usenooutcome'] = 'Use no outcome';
 $string['usenoscale'] = 'Use no scale';
 $string['usepercent'] = 'Use percent';
 $string['user'] = 'User';
+$string['userfields_show'] = 'Show user fields';
+$string['userfields_show_help'] = 'Show additional user fields like email address on the grader report. The specific fields displayed are controlled by the site setting showuseridentity';
 $string['usergrade'] = 'User {$a->fullname} ({$a->useridnumber}) on item {$a->gradeidnumber}';
 $string['userid'] = 'User ID';
 $string['useridnumberwarning'] = 'Users without an ID number are excluded from the export as they cannot be imported';
index 69a706a..b385127 100644 (file)
@@ -654,6 +654,10 @@ class core_plugin_manager {
             return 'git';
         }
 
+        if (is_file($pluginroot.'/.git')) {
+            return 'git-submodule';
+        }
+
         if (is_dir($pluginroot.'/CVS')) {
             return 'cvs';
         }
index d255609..25ba168 100644 (file)
@@ -181,6 +181,10 @@ class deployer {
             return 'git';
         }
 
+        if (is_file($pluginroot.'/.git')) {
+            return 'git-submodule';
+        }
+
         if (is_dir($pluginroot.'/CVS')) {
             return 'cvs';
         }
index 32272de..64c837e 100644 (file)
@@ -171,7 +171,7 @@ function cli_problem($text) {
  * @return void (does not return)
  */
 function cli_error($text, $errorcode=1) {
-    fwrite(STDERR, $text);
+    fwrite(STDERR, "\xE2\x9D\x8C ". $text);
     fwrite(STDERR, "\n");
     die($errorcode);
 }
index bc55e11..e69825f 100644 (file)
@@ -2273,7 +2273,10 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring
 
     if ($forcedownload) {
         header('Content-Disposition: attachment; filename="'.$filename.'"');
-    } else {
+    } else if ($mimetype !== 'application/x-shockwave-flash') {
+        // If this is an swf don't pass content-disposition with filename as this makes the flash player treat the file
+        // as an upload and enforces security that may prevent the file from being loaded.
+
         header('Content-Disposition: inline; filename="'.$filename.'"');
     }
 
index b31c307..36dfb76 100644 (file)
@@ -569,6 +569,8 @@ class grade_category extends grade_object {
             return;
         }
 
+        $minvisible = (bool) get_config('moodle', 'grade_report_showmin');
+
         // normalize the grades first - all will have value 0...1
         // ungraded items are not used in aggregation
         foreach ($grade_values as $itemid=>$v) {
@@ -582,6 +584,10 @@ class grade_category extends grade_object {
                 unset($grade_values[$itemid]);
                 continue;
             }
+            // If grademin is hidden, set it to 0.
+            if (!$minvisible and $items[$itemid]->gradetype != GRADE_TYPE_SCALE) {
+                $items[$itemid]->grademin = 0;
+            }
             $grade_values[$itemid] = grade_grade::standardise_score($v, $items[$itemid]->grademin, $items[$itemid]->grademax, 0, 1);
         }
 
@@ -615,6 +621,10 @@ class grade_category extends grade_object {
         $result = $this->aggregate_values_and_adjust_bounds($grade_values, $items);
         $agg_grade = $result['grade'];
 
+        if (!$minvisible and $this->grade_item->gradetype != GRADE_TYPE_SCALE) {
+            $this->grade_item->grademin = 0;
+        }
+
         // recalculate the grade back to requested range
         $finalgrade = grade_grade::standardise_score($agg_grade, 0, 1, $result['grademin'], $result['grademax']);
 
index e9c6ce4..279af7c 100644 (file)
@@ -243,6 +243,10 @@ class grade_grade extends grade_object {
             return false;
         }
 
+        if ($grade_item->is_course_item() or $grade_item->is_category_item()) {
+            return (bool)get_config('moodle', 'grade_overridecat');
+        }
+
         return true;
     }
 
index 3f8b273..2679146 100644 (file)
@@ -949,7 +949,13 @@ class grade_item extends grade_object {
      * @return bool
      */
     public function is_overridable_item() {
-        return !$this->is_outcome_item() and ($this->is_external_item() or $this->is_calculated() or $this->is_course_item() or $this->is_category_item());
+        if ($this->is_course_item() or $this->is_category_item()) {
+            $overridable = (bool) get_config('moodle', 'grade_overridecat');
+        } else {
+            $overridable = false;
+        }
+
+        return !$this->is_outcome_item() and ($this->is_external_item() or $this->is_calculated() or $overridable);
     }
 
     /**
index 1b9bc93..5ab6c80 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js differ
index 57eddc5..8b58eea 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js differ
index 680a56b..dadf0e8 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js differ
index 2164009..b7788c2 100644 (file)
@@ -147,6 +147,18 @@ Y.extend(DIALOGUE, Y.Panel, {
             this.set('zIndex', zindexvalue);
             if (this.get('modal')) {
                 ol.setStyle('zIndex', zindexvalue);
+
+                // In IE8, the z-indexes do not take effect properly unless you toggle
+                // the lightbox from 'fixed' to 'static' and back. This code does so
+                // using the minimum setTimeouts that still actually work.
+                if (Y.UA.ie && Y.UA.compareVersions(Y.UA.ie, 9) < 0) {
+                    setTimeout(function() {
+                        ol.setStyle('position', 'static');
+                        setTimeout(function() {
+                            ol.setStyle('position', 'fixed');
+                        }, 0);
+                    }, 0);
+                }
             }
             this._calculatedzindex = true;
         }
index 47be101..d6e3dbf 100644 (file)
@@ -1062,8 +1062,9 @@ YAHOO.widget.DateMath = {
 
     /**
      * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
-     * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations 
-     * set the year to 19xx if a year (xx) which is less than 100 is provided.
+     * are set to 0, except the hour which is set to 12 (noon) to avoid issues around the start of Daylight Savings Time. The method allows Date
+     * instances to be created with the a year less than 100. "new Date(year, month, date)" implementations set the year to 19xx if a year (xx)
+     * which is less than 100 is provided.
      * <p>
      * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
      * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
@@ -1080,13 +1081,13 @@ YAHOO.widget.DateMath = {
             d = 1;
         }
         if (y >= 100) {
-            dt = new Date(y, m, d);
+            dt = new Date(y, m, d, 12);
         } else {
             dt = new Date();
             dt.setFullYear(y);
             dt.setMonth(m);
             dt.setDate(d);
-            dt.setHours(0,0,0,0);
+            dt.setHours(12,0,0,0);
         }
         return dt;
     }
index 4e1a063..11ae223 100644 (file)
@@ -8,7 +8,7 @@ http://developer.yahoo.com/yui/license.html
 version: 2.9.0
 */
 (function(){YAHOO.util.Config=function(d){if(d){this.init(d);}};var b=YAHOO.lang,c=YAHOO.util.CustomEvent,a=YAHOO.util.Config;a.CONFIG_CHANGED_EVENT="configChanged";a.BOOLEAN_TYPE="boolean";a.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(d){this.owner=d;this.configChangedEvent=this.createEvent(a.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=c.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(d){return(typeof d==a.BOOLEAN_TYPE);},checkNumber:function(d){return(!isNaN(d));},fireEvent:function(d,f){var e=this.config[d];if(e&&e.event){e.event.fire(f);}},addProperty:function(e,d){e=e.toLowerCase();this.config[e]=d;d.event=this.createEvent(e,{scope:this.owner});d.event.signature=c.LIST;d.key=e;if(d.handler){d.event.subscribe(d.handler,this.owner);}this.setProperty(e,d.value,true);if(!d.suppressEvent){this.queueProperty(e,d.value);}},getConfig:function(){var d={},f=this.config,g,e;for(g in f){if(b.hasOwnProperty(f,g)){e=f[g];if(e&&e.event){d[g]=e.value;}}}return d;},getProperty:function(d){var e=this.config[d.toLowerCase()];if(e&&e.event){return e.value;}else{return undefined;}},resetProperty:function(d){d=d.toLowerCase();var e=this.config[d];if(e&&e.event){if(d in this.initialConfig){this.setProperty(d,this.initialConfig[d]);return true;}}else{return false;}},setProperty:function(e,g,d){var f;e=e.toLowerCase();if(this.queueInProgress&&!d){this.queueProperty(e,g);return true;}else{f=this.config[e];if(f&&f.event){if(f.validator&&!f.validator(g)){return false;}else{f.value=g;if(!d){this.fireEvent(e,g);this.configChangedEvent.fire([e,g]);}return true;}}else{return false;}}},queueProperty:function(v,r){v=v.toLowerCase();var u=this.config[v],l=false,k,g,h,j,p,t,f,n,o,d,m,w,e;if(u&&u.event){if(!b.isUndefined(r)&&u.validator&&!u.validator(r)){return false;}else{if(!b.isUndefined(r)){u.value=r;}else{r=u.value;}l=false;k=this.eventQueue.length;for(m=0;m<k;m++){g=this.eventQueue[m];if(g){h=g[0];j=g[1];if(h==v){this.eventQueue[m]=null;this.eventQueue.push([v,(!b.isUndefined(r)?r:j)]);l=true;break;}}}if(!l&&!b.isUndefined(r)){this.eventQueue.push([v,r]);}}if(u.supercedes){p=u.supercedes.length;for(w=0;w<p;w++){t=u.supercedes[w];f=this.eventQueue.length;for(e=0;e<f;e++){n=this.eventQueue[e];if(n){o=n[0];d=n[1];if(o==t.toLowerCase()){this.eventQueue.push([o,d]);this.eventQueue[e]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(d){d=d.toLowerCase();var e=this.config[d];if(e&&e.event&&!b.isUndefined(e.value)){if(this.queueInProgress){this.queueProperty(d);}else{this.fireEvent(d,e.value);}}},applyConfig:function(d,g){var f,e;if(g){e={};for(f in d){if(b.hasOwnProperty(d,f)){e[f.toLowerCase()]=d[f];}}this.initialConfig=e;}for(f in d){if(b.hasOwnProperty(d,f)){this.queueProperty(f,d[f]);}}},refresh:function(){var d;for(d in this.config){if(b.hasOwnProperty(this.config,d)){this.refireEvent(d);}}},fireQueue:function(){var e,h,d,g,f;this.queueInProgress=true;for(e=0;e<this.eventQueue.length;e++){h=this.eventQueue[e];if(h){d=h[0];g=h[1];f=this.config[d];f.value=g;this.eventQueue[e]=null;this.fireEvent(d,g);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(d,e,g,h){var f=this.config[d.toLowerCase()];if(f&&f.event){if(!a.alreadySubscribed(f.event,e,g)){f.event.subscribe(e,g,h);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(d,e,g){var f=this.config[d.toLowerCase()];if(f&&f.event){return f.event.unsubscribe(e,g);}else{return false;}},toString:function(){var d="Config";if(this.owner){d+=" ["+this.owner.toString()+"]";}return d;},outputEventQueue:function(){var d="",g,e,f=this.eventQueue.length;for(e=0;e<f;e++){g=this.eventQueue[e];if(g){d+=g[0]+"="+g[1]+", ";}}return d;},destroy:function(){var e=this.config,d,f;for(d in e){if(b.hasOwnProperty(e,d)){f=e[d];f.event.unsubscribeAll();f.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};a.alreadySubscribed=function(e,h,j){var f=e.subscribers.length,d,g;if(f>0){g=f-1;do{d=e.subscribers[g];if(d&&d.obj==j&&d.fn==h){return true;}}while(g--);}return false;};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);}());YAHOO.widget.DateMath={DAY:"D",WEEK:"W",YEAR:"Y",MONTH:"M",ONE_DAY_MS:1000*60*60*24,WEEK_ONE_JAN_DATE:1,add:function(a,e,c){var g=new Date(a.getTime());switch(e){case this.MONTH:var f=a.getMonth()+c;var b=0;if(f<0){while(f<0){f+=12;b-=1;}}else{if(f>11){while(f>11){f-=12;b+=1;}}}g.setMonth(f);g.setFullYear(a.getFullYear()+b);break;case this.DAY:this._addDays(g,c);break;case this.YEAR:g.setFullYear(a.getFullYear()+c);break;case this.WEEK:this._addDays(g,(c*7));break;}return g;},_addDays:function(e,c){if(YAHOO.env.ua.webkit&&YAHOO.env.ua.webkit<420){if(c<0){for(var b=-128;c<b;c-=b){e.setDate(e.getDate()+b);}}else{for(var a=96;c>a;c-=a){e.setDate(e.getDate()+a);}}}e.setDate(e.getDate()+c);},subtract:function(a,c,b){return this.add(a,c,(b*-1));},before:function(c,b){var a=b.getTime();if(c.getTime()<a){return true;}else{return false;}},after:function(c,b){var a=b.getTime();if(c.getTime()>a){return true;}else{return false;}},between:function(b,a,c){if(this.after(b,a)&&this.before(b,c)){return true;}else{return false;}},getJan1:function(a){return this.getDate(a,0,1);},getDayOffset:function(b,d){var c=this.getJan1(d);var a=Math.ceil((b.getTime()-c.getTime())/this.ONE_DAY_MS);return a;},getWeekNumber:function(d,b,g){b=b||0;g=g||this.WEEK_ONE_JAN_DATE;var h=this.clearTime(d),l,m;if(h.getDay()===b){l=h;}else{l=this.getFirstDayOfWeek(h,b);}var i=l.getFullYear();m=new Date(l.getTime()+6*this.ONE_DAY_MS);var f;if(i!==m.getFullYear()&&m.getDate()>=g){f=1;}else{var e=this.clearTime(this.getDate(i,0,g)),a=this.getFirstDayOfWeek(e,b);var j=Math.round((h.getTime()-a.getTime())/this.ONE_DAY_MS);var k=j%7;var c=(j-k)/7;f=c+1;}return f;},getFirstDayOfWeek:function(d,a){a=a||0;
-var b=d.getDay(),c=(b-a+7)%7;return this.subtract(d,this.DAY,c);},isYearOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getFullYear()!=a.getFullYear()){c=true;}return c;},isMonthOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getMonth()!=a.getMonth()){c=true;}return c;},findMonthStart:function(a){var b=this.getDate(a.getFullYear(),a.getMonth(),1);return b;},findMonthEnd:function(b){var d=this.findMonthStart(b);var c=this.add(d,this.MONTH,1);var a=this.subtract(c,this.DAY,1);return a;},clearTime:function(a){a.setHours(12,0,0,0);return a;},getDate:function(e,a,c){var b=null;if(YAHOO.lang.isUndefined(c)){c=1;}if(e>=100){b=new Date(e,a,c);}else{b=new Date();b.setFullYear(e);b.setMonth(a);b.setDate(c);b.setHours(0,0,0,0);}return b;}};(function(){var c=YAHOO.util.Dom,a=YAHOO.util.Event,e=YAHOO.lang,d=YAHOO.widget.DateMath;function f(i,g,h){this.init.apply(this,arguments);}f.IMG_ROOT=null;f.DATE="D";f.MONTH_DAY="MD";f.WEEKDAY="WD";f.RANGE="R";f.MONTH="M";f.DISPLAY_DAYS=42;f.STOP_RENDER="S";f.SHORT="short";f.LONG="long";f.MEDIUM="medium";f.ONE_CHAR="1char";f.DEFAULT_CONFIG={YEAR_OFFSET:{key:"year_offset",value:0,supercedes:["pagedate","selected","mindate","maxdate"]},TODAY:{key:"today",value:new Date(),supercedes:["pagedate"]},PAGEDATE:{key:"pagedate",value:null},SELECTED:{key:"selected",value:[]},TITLE:{key:"title",value:""},CLOSE:{key:"close",value:false},IFRAME:{key:"iframe",value:(YAHOO.env.ua.ie&&YAHOO.env.ua.ie<=6)?true:false},MINDATE:{key:"mindate",value:null},MAXDATE:{key:"maxdate",value:null},MULTI_SELECT:{key:"multi_select",value:false},OOM_SELECT:{key:"oom_select",value:false},START_WEEKDAY:{key:"start_weekday",value:0},SHOW_WEEKDAYS:{key:"show_weekdays",value:true},SHOW_WEEK_HEADER:{key:"show_week_header",value:false},SHOW_WEEK_FOOTER:{key:"show_week_footer",value:false},HIDE_BLANK_WEEKS:{key:"hide_blank_weeks",value:false},NAV_ARROW_LEFT:{key:"nav_arrow_left",value:null},NAV_ARROW_RIGHT:{key:"nav_arrow_right",value:null},MONTHS_SHORT:{key:"months_short",value:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},MONTHS_LONG:{key:"months_long",value:["January","February","March","April","May","June","July","August","September","October","November","December"]},WEEKDAYS_1CHAR:{key:"weekdays_1char",value:["S","M","T","W","T","F","S"]},WEEKDAYS_SHORT:{key:"weekdays_short",value:["Su","Mo","Tu","We","Th","Fr","Sa"]},WEEKDAYS_MEDIUM:{key:"weekdays_medium",value:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},WEEKDAYS_LONG:{key:"weekdays_long",value:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},LOCALE_MONTHS:{key:"locale_months",value:"long"},LOCALE_WEEKDAYS:{key:"locale_weekdays",value:"short"},DATE_DELIMITER:{key:"date_delimiter",value:","},DATE_FIELD_DELIMITER:{key:"date_field_delimiter",value:"/"},DATE_RANGE_DELIMITER:{key:"date_range_delimiter",value:"-"},MY_MONTH_POSITION:{key:"my_month_position",value:1},MY_YEAR_POSITION:{key:"my_year_position",value:2},MD_MONTH_POSITION:{key:"md_month_position",value:1},MD_DAY_POSITION:{key:"md_day_position",value:2},MDY_MONTH_POSITION:{key:"mdy_month_position",value:1},MDY_DAY_POSITION:{key:"mdy_day_position",value:2},MDY_YEAR_POSITION:{key:"mdy_year_position",value:3},MY_LABEL_MONTH_POSITION:{key:"my_label_month_position",value:1},MY_LABEL_YEAR_POSITION:{key:"my_label_year_position",value:2},MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix",value:" "},MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix",value:""},NAV:{key:"navigator",value:null},STRINGS:{key:"strings",value:{previousMonth:"Previous Month",nextMonth:"Next Month",close:"Close"},supercedes:["close","title"]}};f._DEFAULT_CONFIG=f.DEFAULT_CONFIG;var b=f.DEFAULT_CONFIG;f._EVENT_TYPES={BEFORE_SELECT:"beforeSelect",SELECT:"select",BEFORE_DESELECT:"beforeDeselect",DESELECT:"deselect",CHANGE_PAGE:"changePage",BEFORE_RENDER:"beforeRender",RENDER:"render",BEFORE_DESTROY:"beforeDestroy",DESTROY:"destroy",RESET:"reset",CLEAR:"clear",BEFORE_HIDE:"beforeHide",HIDE:"hide",BEFORE_SHOW:"beforeShow",SHOW:"show",BEFORE_HIDE_NAV:"beforeHideNav",HIDE_NAV:"hideNav",BEFORE_SHOW_NAV:"beforeShowNav",SHOW_NAV:"showNav",BEFORE_RENDER_NAV:"beforeRenderNav",RENDER_NAV:"renderNav"};f.STYLES={CSS_ROW_HEADER:"calrowhead",CSS_ROW_FOOTER:"calrowfoot",CSS_CELL:"calcell",CSS_CELL_SELECTOR:"selector",CSS_CELL_SELECTED:"selected",CSS_CELL_SELECTABLE:"selectable",CSS_CELL_RESTRICTED:"restricted",CSS_CELL_TODAY:"today",CSS_CELL_OOM:"oom",CSS_CELL_OOB:"previous",CSS_HEADER:"calheader",CSS_HEADER_TEXT:"calhead",CSS_BODY:"calbody",CSS_WEEKDAY_CELL:"calweekdaycell",CSS_WEEKDAY_ROW:"calweekdayrow",CSS_FOOTER:"calfoot",CSS_CALENDAR:"yui-calendar",CSS_SINGLE:"single",CSS_CONTAINER:"yui-calcontainer",CSS_NAV_LEFT:"calnavleft",CSS_NAV_RIGHT:"calnavright",CSS_NAV:"calnav",CSS_CLOSE:"calclose",CSS_CELL_TOP:"calcelltop",CSS_CELL_LEFT:"calcellleft",CSS_CELL_RIGHT:"calcellright",CSS_CELL_BOTTOM:"calcellbottom",CSS_CELL_HOVER:"calcellhover",CSS_CELL_HIGHLIGHT1:"highlight1",CSS_CELL_HIGHLIGHT2:"highlight2",CSS_CELL_HIGHLIGHT3:"highlight3",CSS_CELL_HIGHLIGHT4:"highlight4",CSS_WITH_TITLE:"withtitle",CSS_FIXED_SIZE:"fixedsize",CSS_LINK_CLOSE:"link-close"};f._STYLES=f.STYLES;f.prototype={Config:null,parent:null,index:-1,cells:null,cellDates:null,id:null,containerId:null,oDomContainer:null,today:null,renderStack:null,_renderStack:null,oNavigator:null,_selectedDates:null,domEventMap:null,_parseArgs:function(h){var g={id:null,container:null,config:null};if(h&&h.length&&h.length>0){switch(h.length){case 1:g.id=null;g.container=h[0];g.config=null;break;case 2:if(e.isObject(h[1])&&!h[1].tagName&&!(h[1] instanceof String)){g.id=null;g.container=h[0];g.config=h[1];}else{g.id=h[0];g.container=h[1];g.config=null;}break;default:g.id=h[0];g.container=h[1];g.config=h[2];break;}}else{}return g;},init:function(j,h,i){var g=this._parseArgs(arguments);j=g.id;h=g.container;i=g.config;this.oDomContainer=c.get(h);this._oDoc=this.oDomContainer.ownerDocument;if(!this.oDomContainer.id){this.oDomContainer.id=c.generateId();
+var b=d.getDay(),c=(b-a+7)%7;return this.subtract(d,this.DAY,c);},isYearOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getFullYear()!=a.getFullYear()){c=true;}return c;},isMonthOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getMonth()!=a.getMonth()){c=true;}return c;},findMonthStart:function(a){var b=this.getDate(a.getFullYear(),a.getMonth(),1);return b;},findMonthEnd:function(b){var d=this.findMonthStart(b);var c=this.add(d,this.MONTH,1);var a=this.subtract(c,this.DAY,1);return a;},clearTime:function(a){a.setHours(12,0,0,0);return a;},getDate:function(e,a,c){var b=null;if(YAHOO.lang.isUndefined(c)){c=1;}if(e>=100){b=new Date(e,a,c,12);}else{b=new Date();b.setFullYear(e);b.setMonth(a);b.setDate(c);b.setHours(12,0,0,0);}return b;}};(function(){var c=YAHOO.util.Dom,a=YAHOO.util.Event,e=YAHOO.lang,d=YAHOO.widget.DateMath;function f(i,g,h){this.init.apply(this,arguments);}f.IMG_ROOT=null;f.DATE="D";f.MONTH_DAY="MD";f.WEEKDAY="WD";f.RANGE="R";f.MONTH="M";f.DISPLAY_DAYS=42;f.STOP_RENDER="S";f.SHORT="short";f.LONG="long";f.MEDIUM="medium";f.ONE_CHAR="1char";f.DEFAULT_CONFIG={YEAR_OFFSET:{key:"year_offset",value:0,supercedes:["pagedate","selected","mindate","maxdate"]},TODAY:{key:"today",value:new Date(),supercedes:["pagedate"]},PAGEDATE:{key:"pagedate",value:null},SELECTED:{key:"selected",value:[]},TITLE:{key:"title",value:""},CLOSE:{key:"close",value:false},IFRAME:{key:"iframe",value:(YAHOO.env.ua.ie&&YAHOO.env.ua.ie<=6)?true:false},MINDATE:{key:"mindate",value:null},MAXDATE:{key:"maxdate",value:null},MULTI_SELECT:{key:"multi_select",value:false},OOM_SELECT:{key:"oom_select",value:false},START_WEEKDAY:{key:"start_weekday",value:0},SHOW_WEEKDAYS:{key:"show_weekdays",value:true},SHOW_WEEK_HEADER:{key:"show_week_header",value:false},SHOW_WEEK_FOOTER:{key:"show_week_footer",value:false},HIDE_BLANK_WEEKS:{key:"hide_blank_weeks",value:false},NAV_ARROW_LEFT:{key:"nav_arrow_left",value:null},NAV_ARROW_RIGHT:{key:"nav_arrow_right",value:null},MONTHS_SHORT:{key:"months_short",value:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]},MONTHS_LONG:{key:"months_long",value:["January","February","March","April","May","June","July","August","September","October","November","December"]},WEEKDAYS_1CHAR:{key:"weekdays_1char",value:["S","M","T","W","T","F","S"]},WEEKDAYS_SHORT:{key:"weekdays_short",value:["Su","Mo","Tu","We","Th","Fr","Sa"]},WEEKDAYS_MEDIUM:{key:"weekdays_medium",value:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]},WEEKDAYS_LONG:{key:"weekdays_long",value:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},LOCALE_MONTHS:{key:"locale_months",value:"long"},LOCALE_WEEKDAYS:{key:"locale_weekdays",value:"short"},DATE_DELIMITER:{key:"date_delimiter",value:","},DATE_FIELD_DELIMITER:{key:"date_field_delimiter",value:"/"},DATE_RANGE_DELIMITER:{key:"date_range_delimiter",value:"-"},MY_MONTH_POSITION:{key:"my_month_position",value:1},MY_YEAR_POSITION:{key:"my_year_position",value:2},MD_MONTH_POSITION:{key:"md_month_position",value:1},MD_DAY_POSITION:{key:"md_day_position",value:2},MDY_MONTH_POSITION:{key:"mdy_month_position",value:1},MDY_DAY_POSITION:{key:"mdy_day_position",value:2},MDY_YEAR_POSITION:{key:"mdy_year_position",value:3},MY_LABEL_MONTH_POSITION:{key:"my_label_month_position",value:1},MY_LABEL_YEAR_POSITION:{key:"my_label_year_position",value:2},MY_LABEL_MONTH_SUFFIX:{key:"my_label_month_suffix",value:" "},MY_LABEL_YEAR_SUFFIX:{key:"my_label_year_suffix",value:""},NAV:{key:"navigator",value:null},STRINGS:{key:"strings",value:{previousMonth:"Previous Month",nextMonth:"Next Month",close:"Close"},supercedes:["close","title"]}};f._DEFAULT_CONFIG=f.DEFAULT_CONFIG;var b=f.DEFAULT_CONFIG;f._EVENT_TYPES={BEFORE_SELECT:"beforeSelect",SELECT:"select",BEFORE_DESELECT:"beforeDeselect",DESELECT:"deselect",CHANGE_PAGE:"changePage",BEFORE_RENDER:"beforeRender",RENDER:"render",BEFORE_DESTROY:"beforeDestroy",DESTROY:"destroy",RESET:"reset",CLEAR:"clear",BEFORE_HIDE:"beforeHide",HIDE:"hide",BEFORE_SHOW:"beforeShow",SHOW:"show",BEFORE_HIDE_NAV:"beforeHideNav",HIDE_NAV:"hideNav",BEFORE_SHOW_NAV:"beforeShowNav",SHOW_NAV:"showNav",BEFORE_RENDER_NAV:"beforeRenderNav",RENDER_NAV:"renderNav"};f.STYLES={CSS_ROW_HEADER:"calrowhead",CSS_ROW_FOOTER:"calrowfoot",CSS_CELL:"calcell",CSS_CELL_SELECTOR:"selector",CSS_CELL_SELECTED:"selected",CSS_CELL_SELECTABLE:"selectable",CSS_CELL_RESTRICTED:"restricted",CSS_CELL_TODAY:"today",CSS_CELL_OOM:"oom",CSS_CELL_OOB:"previous",CSS_HEADER:"calheader",CSS_HEADER_TEXT:"calhead",CSS_BODY:"calbody",CSS_WEEKDAY_CELL:"calweekdaycell",CSS_WEEKDAY_ROW:"calweekdayrow",CSS_FOOTER:"calfoot",CSS_CALENDAR:"yui-calendar",CSS_SINGLE:"single",CSS_CONTAINER:"yui-calcontainer",CSS_NAV_LEFT:"calnavleft",CSS_NAV_RIGHT:"calnavright",CSS_NAV:"calnav",CSS_CLOSE:"calclose",CSS_CELL_TOP:"calcelltop",CSS_CELL_LEFT:"calcellleft",CSS_CELL_RIGHT:"calcellright",CSS_CELL_BOTTOM:"calcellbottom",CSS_CELL_HOVER:"calcellhover",CSS_CELL_HIGHLIGHT1:"highlight1",CSS_CELL_HIGHLIGHT2:"highlight2",CSS_CELL_HIGHLIGHT3:"highlight3",CSS_CELL_HIGHLIGHT4:"highlight4",CSS_WITH_TITLE:"withtitle",CSS_FIXED_SIZE:"fixedsize",CSS_LINK_CLOSE:"link-close"};f._STYLES=f.STYLES;f.prototype={Config:null,parent:null,index:-1,cells:null,cellDates:null,id:null,containerId:null,oDomContainer:null,today:null,renderStack:null,_renderStack:null,oNavigator:null,_selectedDates:null,domEventMap:null,_parseArgs:function(h){var g={id:null,container:null,config:null};if(h&&h.length&&h.length>0){switch(h.length){case 1:g.id=null;g.container=h[0];g.config=null;break;case 2:if(e.isObject(h[1])&&!h[1].tagName&&!(h[1] instanceof String)){g.id=null;g.container=h[0];g.config=h[1];}else{g.id=h[0];g.container=h[1];g.config=null;}break;default:g.id=h[0];g.container=h[1];g.config=h[2];break;}}else{}return g;},init:function(j,h,i){var g=this._parseArgs(arguments);j=g.id;h=g.container;i=g.config;this.oDomContainer=c.get(h);this._oDoc=this.oDomContainer.ownerDocument;if(!this.oDomContainer.id){this.oDomContainer.id=c.generateId();
 }if(!j){j=this.oDomContainer.id+"_t";}this.id=j;this.containerId=this.oDomContainer.id;this.initEvents();this.cfg=new YAHOO.util.Config(this);this.Options={};this.Locale={};this.initStyles();c.addClass(this.oDomContainer,this.Style.CSS_CONTAINER);c.addClass(this.oDomContainer,this.Style.CSS_SINGLE);this.cellDates=[];this.cells=[];this.renderStack=[];this._renderStack=[];this.setupConfig();if(i){this.cfg.applyConfig(i,true);}this.cfg.fireQueue();this.today=this.cfg.getProperty("today");},configIframe:function(i,h,j){var g=h[0];if(!this.parent){if(c.inDocument(this.oDomContainer)){if(g){var k=c.getStyle(this.oDomContainer,"position");if(k=="absolute"||k=="relative"){if(!c.inDocument(this.iframe)){this.iframe=document.createElement("iframe");this.iframe.src="javascript:false;";c.setStyle(this.iframe,"opacity","0");if(YAHOO.env.ua.ie&&YAHOO.env.ua.ie<=6){c.addClass(this.iframe,this.Style.CSS_FIXED_SIZE);}this.oDomContainer.insertBefore(this.iframe,this.oDomContainer.firstChild);}}}else{if(this.iframe){if(this.iframe.parentNode){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;}}}}},configTitle:function(h,g,i){var k=g[0];if(k){this.createTitleBar(k);}else{var j=this.cfg.getProperty(b.CLOSE.key);if(!j){this.removeTitleBar();}else{this.createTitleBar("&#160;");}}},configClose:function(h,g,i){var k=g[0],j=this.cfg.getProperty(b.TITLE.key);if(k){if(!j){this.createTitleBar("&#160;");}this.createCloseButton();}else{this.removeCloseButton();if(!j){this.removeTitleBar();}}},initEvents:function(){var g=f._EVENT_TYPES,i=YAHOO.util.CustomEvent,h=this;h.beforeSelectEvent=new i(g.BEFORE_SELECT);h.selectEvent=new i(g.SELECT);h.beforeDeselectEvent=new i(g.BEFORE_DESELECT);h.deselectEvent=new i(g.DESELECT);h.changePageEvent=new i(g.CHANGE_PAGE);h.beforeRenderEvent=new i(g.BEFORE_RENDER);h.renderEvent=new i(g.RENDER);h.beforeDestroyEvent=new i(g.BEFORE_DESTROY);h.destroyEvent=new i(g.DESTROY);h.resetEvent=new i(g.RESET);h.clearEvent=new i(g.CLEAR);h.beforeShowEvent=new i(g.BEFORE_SHOW);h.showEvent=new i(g.SHOW);h.beforeHideEvent=new i(g.BEFORE_HIDE);h.hideEvent=new i(g.HIDE);h.beforeShowNavEvent=new i(g.BEFORE_SHOW_NAV);h.showNavEvent=new i(g.SHOW_NAV);h.beforeHideNavEvent=new i(g.BEFORE_HIDE_NAV);h.hideNavEvent=new i(g.HIDE_NAV);h.beforeRenderNavEvent=new i(g.BEFORE_RENDER_NAV);h.renderNavEvent=new i(g.RENDER_NAV);h.beforeSelectEvent.subscribe(h.onBeforeSelect,this,true);h.selectEvent.subscribe(h.onSelect,this,true);h.beforeDeselectEvent.subscribe(h.onBeforeDeselect,this,true);h.deselectEvent.subscribe(h.onDeselect,this,true);h.changePageEvent.subscribe(h.onChangePage,this,true);h.renderEvent.subscribe(h.onRender,this,true);h.resetEvent.subscribe(h.onReset,this,true);h.clearEvent.subscribe(h.onClear,this,true);},doPreviousMonthNav:function(h,g){a.preventDefault(h);setTimeout(function(){g.previousMonth();var j=c.getElementsByClassName(g.Style.CSS_NAV_LEFT,"a",g.oDomContainer);if(j&&j[0]){try{j[0].focus();}catch(i){}}},0);},doNextMonthNav:function(h,g){a.preventDefault(h);setTimeout(function(){g.nextMonth();var j=c.getElementsByClassName(g.Style.CSS_NAV_RIGHT,"a",g.oDomContainer);if(j&&j[0]){try{j[0].focus();}catch(i){}}},0);},doSelectCell:function(m,g){var r,o,i,l;var n=a.getTarget(m),h=n.tagName.toLowerCase(),k=false;while(h!="td"&&!c.hasClass(n,g.Style.CSS_CELL_SELECTABLE)){if(!k&&h=="a"&&c.hasClass(n,g.Style.CSS_CELL_SELECTOR)){k=true;}n=n.parentNode;h=n.tagName.toLowerCase();if(n==this.oDomContainer||h=="html"){return;}}if(k){a.preventDefault(m);}r=n;if(c.hasClass(r,g.Style.CSS_CELL_SELECTABLE)){l=g.getIndexFromId(r.id);if(l>-1){o=g.cellDates[l];if(o){i=d.getDate(o[0],o[1]-1,o[2]);var q;if(g.Options.MULTI_SELECT){q=r.getElementsByTagName("a")[0];if(q){q.blur();}var j=g.cellDates[l];var p=g._indexOfSelectedFieldArray(j);if(p>-1){g.deselectCell(l);}else{g.selectCell(l);}}else{q=r.getElementsByTagName("a")[0];if(q){q.blur();}g.selectCell(l);}}}}},doCellMouseOver:function(i,h){var g;if(i){g=a.getTarget(i);}else{g=this;}while(g.tagName&&g.tagName.toLowerCase()!="td"){g=g.parentNode;if(!g.tagName||g.tagName.toLowerCase()=="html"){return;}}if(c.hasClass(g,h.Style.CSS_CELL_SELECTABLE)){c.addClass(g,h.Style.CSS_CELL_HOVER);}},doCellMouseOut:function(i,h){var g;if(i){g=a.getTarget(i);}else{g=this;}while(g.tagName&&g.tagName.toLowerCase()!="td"){g=g.parentNode;if(!g.tagName||g.tagName.toLowerCase()=="html"){return;}}if(c.hasClass(g,h.Style.CSS_CELL_SELECTABLE)){c.removeClass(g,h.Style.CSS_CELL_HOVER);}},setupConfig:function(){var g=this.cfg;g.addProperty(b.TODAY.key,{value:new Date(b.TODAY.value.getTime()),supercedes:b.TODAY.supercedes,handler:this.configToday,suppressEvent:true});g.addProperty(b.PAGEDATE.key,{value:b.PAGEDATE.value||new Date(b.TODAY.value.getTime()),handler:this.configPageDate});g.addProperty(b.SELECTED.key,{value:b.SELECTED.value.concat(),handler:this.configSelected});g.addProperty(b.TITLE.key,{value:b.TITLE.value,handler:this.configTitle});g.addProperty(b.CLOSE.key,{value:b.CLOSE.value,handler:this.configClose});g.addProperty(b.IFRAME.key,{value:b.IFRAME.value,handler:this.configIframe,validator:g.checkBoolean});g.addProperty(b.MINDATE.key,{value:b.MINDATE.value,handler:this.configMinDate});g.addProperty(b.MAXDATE.key,{value:b.MAXDATE.value,handler:this.configMaxDate});g.addProperty(b.MULTI_SELECT.key,{value:b.MULTI_SELECT.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.OOM_SELECT.key,{value:b.OOM_SELECT.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.START_WEEKDAY.key,{value:b.START_WEEKDAY.value,handler:this.configOptions,validator:g.checkNumber});g.addProperty(b.SHOW_WEEKDAYS.key,{value:b.SHOW_WEEKDAYS.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.SHOW_WEEK_HEADER.key,{value:b.SHOW_WEEK_HEADER.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.SHOW_WEEK_FOOTER.key,{value:b.SHOW_WEEK_FOOTER.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.HIDE_BLANK_WEEKS.key,{value:b.HIDE_BLANK_WEEKS.value,handler:this.configOptions,validator:g.checkBoolean});
 g.addProperty(b.NAV_ARROW_LEFT.key,{value:b.NAV_ARROW_LEFT.value,handler:this.configOptions});g.addProperty(b.NAV_ARROW_RIGHT.key,{value:b.NAV_ARROW_RIGHT.value,handler:this.configOptions});g.addProperty(b.MONTHS_SHORT.key,{value:b.MONTHS_SHORT.value,handler:this.configLocale});g.addProperty(b.MONTHS_LONG.key,{value:b.MONTHS_LONG.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_1CHAR.key,{value:b.WEEKDAYS_1CHAR.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_SHORT.key,{value:b.WEEKDAYS_SHORT.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_MEDIUM.key,{value:b.WEEKDAYS_MEDIUM.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_LONG.key,{value:b.WEEKDAYS_LONG.value,handler:this.configLocale});var h=function(){g.refireEvent(b.LOCALE_MONTHS.key);g.refireEvent(b.LOCALE_WEEKDAYS.key);};g.subscribeToConfigEvent(b.START_WEEKDAY.key,h,this,true);g.subscribeToConfigEvent(b.MONTHS_SHORT.key,h,this,true);g.subscribeToConfigEvent(b.MONTHS_LONG.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_1CHAR.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_SHORT.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_MEDIUM.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_LONG.key,h,this,true);g.addProperty(b.LOCALE_MONTHS.key,{value:b.LOCALE_MONTHS.value,handler:this.configLocaleValues});g.addProperty(b.LOCALE_WEEKDAYS.key,{value:b.LOCALE_WEEKDAYS.value,handler:this.configLocaleValues});g.addProperty(b.YEAR_OFFSET.key,{value:b.YEAR_OFFSET.value,supercedes:b.YEAR_OFFSET.supercedes,handler:this.configLocale});g.addProperty(b.DATE_DELIMITER.key,{value:b.DATE_DELIMITER.value,handler:this.configLocale});g.addProperty(b.DATE_FIELD_DELIMITER.key,{value:b.DATE_FIELD_DELIMITER.value,handler:this.configLocale});g.addProperty(b.DATE_RANGE_DELIMITER.key,{value:b.DATE_RANGE_DELIMITER.value,handler:this.configLocale});g.addProperty(b.MY_MONTH_POSITION.key,{value:b.MY_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_YEAR_POSITION.key,{value:b.MY_YEAR_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MD_MONTH_POSITION.key,{value:b.MD_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MD_DAY_POSITION.key,{value:b.MD_DAY_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_MONTH_POSITION.key,{value:b.MDY_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_DAY_POSITION.key,{value:b.MDY_DAY_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_YEAR_POSITION.key,{value:b.MDY_YEAR_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_LABEL_MONTH_POSITION.key,{value:b.MY_LABEL_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_LABEL_YEAR_POSITION.key,{value:b.MY_LABEL_YEAR_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_LABEL_MONTH_SUFFIX.key,{value:b.MY_LABEL_MONTH_SUFFIX.value,handler:this.configLocale});g.addProperty(b.MY_LABEL_YEAR_SUFFIX.key,{value:b.MY_LABEL_YEAR_SUFFIX.value,handler:this.configLocale});g.addProperty(b.NAV.key,{value:b.NAV.value,handler:this.configNavigator});g.addProperty(b.STRINGS.key,{value:b.STRINGS.value,handler:this.configStrings,validator:function(i){return e.isObject(i);},supercedes:b.STRINGS.supercedes});},configStrings:function(h,g,i){var j=e.merge(b.STRINGS.value,g[0]);this.cfg.setProperty(b.STRINGS.key,j,true);},configPageDate:function(h,g,i){this.cfg.setProperty(b.PAGEDATE.key,this._parsePageDate(g[0]),true);},configMinDate:function(h,g,i){var j=g[0];if(e.isString(j)){j=this._parseDate(j);this.cfg.setProperty(b.MINDATE.key,d.getDate(j[0],(j[1]-1),j[2]));}},configMaxDate:function(h,g,i){var j=g[0];if(e.isString(j)){j=this._parseDate(j);this.cfg.setProperty(b.MAXDATE.key,d.getDate(j[0],(j[1]-1),j[2]));}},configToday:function(i,h,j){var k=h[0];if(e.isString(k)){k=this._parseDate(k);}var g=d.clearTime(k);if(!this.cfg.initialConfig[b.PAGEDATE.key]){this.cfg.setProperty(b.PAGEDATE.key,g);}this.today=g;this.cfg.setProperty(b.TODAY.key,g,true);},configSelected:function(i,g,k){var h=g[0],j=b.SELECTED.key;if(h){if(e.isString(h)){this.cfg.setProperty(j,this._parseDates(h),true);}}if(!this._selectedDates){this._selectedDates=this.cfg.getProperty(j);}},configOptions:function(h,g,i){this.Options[h.toUpperCase()]=g[0];},configLocale:function(h,g,i){this.Locale[h.toUpperCase()]=g[0];this.cfg.refireEvent(b.LOCALE_MONTHS.key);this.cfg.refireEvent(b.LOCALE_WEEKDAYS.key);},configLocaleValues:function(j,i,k){j=j.toLowerCase();var m=i[0],h=this.cfg,n=this.Locale;switch(j){case b.LOCALE_MONTHS.key:switch(m){case f.SHORT:n.LOCALE_MONTHS=h.getProperty(b.MONTHS_SHORT.key).concat();break;case f.LONG:n.LOCALE_MONTHS=h.getProperty(b.MONTHS_LONG.key).concat();break;}break;case b.LOCALE_WEEKDAYS.key:switch(m){case f.ONE_CHAR:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_1CHAR.key).concat();break;case f.SHORT:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_SHORT.key).concat();break;case f.MEDIUM:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_MEDIUM.key).concat();break;case f.LONG:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_LONG.key).concat();break;}var l=h.getProperty(b.START_WEEKDAY.key);if(l>0){for(var g=0;g<l;++g){n.LOCALE_WEEKDAYS.push(n.LOCALE_WEEKDAYS.shift());}}break;}},configNavigator:function(h,g,i){var j=g[0];if(YAHOO.widget.CalendarNavigator&&(j===true||e.isObject(j))){if(!this.oNavigator){this.oNavigator=new YAHOO.widget.CalendarNavigator(this);this.beforeRenderEvent.subscribe(function(){if(!this.pages){this.oNavigator.erase();}},this,true);}}else{if(this.oNavigator){this.oNavigator.destroy();this.oNavigator=null;}}},initStyles:function(){var g=f.STYLES;this.Style={CSS_ROW_HEADER:g.CSS_ROW_HEADER,CSS_ROW_FOOTER:g.CSS_ROW_FOOTER,CSS_CELL:g.CSS_CELL,CSS_CELL_SELECTOR:g.CSS_CELL_SELECTOR,CSS_CELL_SELECTED:g.CSS_CELL_SELECTED,CSS_CELL_SELECTABLE:g.CSS_CELL_SELECTABLE,CSS_CELL_RESTRICTED:g.CSS_CELL_RESTRICTED,CSS_CELL_TODAY:g.CSS_CELL_TODAY,CSS_CELL_OOM:g.CSS_CELL_OOM,CSS_CELL_OOB:g.CSS_CELL_OOB,CSS_HEADER:g.CSS_HEADER,CSS_HEADER_TEXT:g.CSS_HEADER_TEXT,CSS_BODY:g.CSS_BODY,CSS_WEEKDAY_CELL:g.CSS_WEEKDAY_CELL,CSS_WEEKDAY_ROW:g.CSS_WEEKDAY_ROW,CSS_FOOTER:g.CSS_FOOTER,CSS_CALENDAR:g.CSS_CALENDAR,CSS_SINGLE:g.CSS_SINGLE,CSS_CONTAINER:g.CSS_CONTAINER,CSS_NAV_LEFT:g.CSS_NAV_LEFT,CSS_NAV_RIGHT:g.CSS_NAV_RIGHT,CSS_NAV:g.CSS_NAV,CSS_CLOSE:g.CSS_CLOSE,CSS_CELL_TOP:g.CSS_CELL_TOP,CSS_CELL_LEFT:g.CSS_CELL_LEFT,CSS_CELL_RIGHT:g.CSS_CELL_RIGHT,CSS_CELL_BOTTOM:g.CSS_CELL_BOTTOM,CSS_CELL_HOVER:g.CSS_CELL_HOVER,CSS_CELL_HIGHLIGHT1:g.CSS_CELL_HIGHLIGHT1,CSS_CELL_HIGHLIGHT2:g.CSS_CELL_HIGHLIGHT2,CSS_CELL_HIGHLIGHT3:g.CSS_CELL_HIGHLIGHT3,CSS_CELL_HIGHLIGHT4:g.CSS_CELL_HIGHLIGHT4,CSS_WITH_TITLE:g.CSS_WITH_TITLE,CSS_FIXED_SIZE:g.CSS_FIXED_SIZE,CSS_LINK_CLOSE:g.CSS_LINK_CLOSE};
 },buildMonthLabel:function(){return this._buildMonthLabel(this.cfg.getProperty(b.PAGEDATE.key));},_buildMonthLabel:function(g){var i=this.Locale.LOCALE_MONTHS[g.getMonth()]+this.Locale.MY_LABEL_MONTH_SUFFIX,h=(g.getFullYear()+this.Locale.YEAR_OFFSET)+this.Locale.MY_LABEL_YEAR_SUFFIX;if(this.Locale.MY_LABEL_MONTH_POSITION==2||this.Locale.MY_LABEL_YEAR_POSITION==1){return h+i;}else{return i+h;}},buildDayLabel:function(g){return g.getDate();},createTitleBar:function(g){var h=c.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,"div",this.oDomContainer)[0]||document.createElement("div");h.className=YAHOO.widget.CalendarGroup.CSS_2UPTITLE;h.innerHTML=g;this.oDomContainer.insertBefore(h,this.oDomContainer.firstChild);c.addClass(this.oDomContainer,this.Style.CSS_WITH_TITLE);return h;},removeTitleBar:function(){var g=c.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,"div",this.oDomContainer)[0]||null;if(g){a.purgeElement(g);this.oDomContainer.removeChild(g);}c.removeClass(this.oDomContainer,this.Style.CSS_WITH_TITLE);},createCloseButton:function(){var k=YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,j=this.Style.CSS_LINK_CLOSE,m="us/my/bn/x_d.gif",l=c.getElementsByClassName(j,"a",this.oDomContainer)[0],g=this.cfg.getProperty(b.STRINGS.key),h=(g&&g.close)?g.close:"";if(!l){l=document.createElement("a");a.addListener(l,"click",function(o,n){n.hide();a.preventDefault(o);},this);}l.href="#";l.className=j;if(f.IMG_ROOT!==null){var i=c.getElementsByClassName(k,"img",l)[0]||document.createElement("img");i.src=f.IMG_ROOT+m;i.className=k;l.appendChild(i);}else{l.innerHTML='<span class="'+k+" "+this.Style.CSS_CLOSE+'">'+h+"</span>";}this.oDomContainer.appendChild(l);return l;},removeCloseButton:function(){var g=c.getElementsByClassName(this.Style.CSS_LINK_CLOSE,"a",this.oDomContainer)[0]||null;if(g){a.purgeElement(g);this.oDomContainer.removeChild(g);}},renderHeader:function(q){var p=7,o="us/tr/callt.gif",g="us/tr/calrt.gif",n=this.cfg,k=n.getProperty(b.PAGEDATE.key),l=n.getProperty(b.STRINGS.key),v=(l&&l.previousMonth)?l.previousMonth:"",h=(l&&l.nextMonth)?l.nextMonth:"",m;if(n.getProperty(b.SHOW_WEEK_HEADER.key)){p+=1;}if(n.getProperty(b.SHOW_WEEK_FOOTER.key)){p+=1;}q[q.length]="<thead>";q[q.length]="<tr>";q[q.length]='<th colspan="'+p+'" class="'+this.Style.CSS_HEADER_TEXT+'">';q[q.length]='<div class="'+this.Style.CSS_HEADER+'">';var x,u=false;if(this.parent){if(this.index===0){x=true;}if(this.index==(this.parent.cfg.getProperty("pages")-1)){u=true;}}else{x=true;u=true;}if(x){m=this._buildMonthLabel(d.subtract(k,d.MONTH,1));var r=n.getProperty(b.NAV_ARROW_LEFT.key);if(r===null&&f.IMG_ROOT!==null){r=f.IMG_ROOT+o;}var i=(r===null)?"":' style="background-image:url('+r+')"';q[q.length]='<a class="'+this.Style.CSS_NAV_LEFT+'"'+i+' href="#">'+v+" ("+m+")"+"</a>";}var w=this.buildMonthLabel();var s=this.parent||this;if(s.cfg.getProperty("navigator")){w='<a class="'+this.Style.CSS_NAV+'" href="#">'+w+"</a>";}q[q.length]=w;if(u){m=this._buildMonthLabel(d.add(k,d.MONTH,1));var t=n.getProperty(b.NAV_ARROW_RIGHT.key);if(t===null&&f.IMG_ROOT!==null){t=f.IMG_ROOT+g;}var j=(t===null)?"":' style="background-image:url('+t+')"';q[q.length]='<a class="'+this.Style.CSS_NAV_RIGHT+'"'+j+' href="#">'+h+" ("+m+")"+"</a>";}q[q.length]="</div>\n</th>\n</tr>";if(n.getProperty(b.SHOW_WEEKDAYS.key)){q=this.buildWeekdays(q);}q[q.length]="</thead>";return q;},buildWeekdays:function(h){h[h.length]='<tr class="'+this.Style.CSS_WEEKDAY_ROW+'">';if(this.cfg.getProperty(b.SHOW_WEEK_HEADER.key)){h[h.length]="<th>&#160;</th>";}for(var g=0;g<this.Locale.LOCALE_WEEKDAYS.length;++g){h[h.length]='<th class="'+this.Style.CSS_WEEKDAY_CELL+'">'+this.Locale.LOCALE_WEEKDAYS[g]+"</th>";}if(this.cfg.getProperty(b.SHOW_WEEK_FOOTER.key)){h[h.length]="<th>&#160;</th>";}h[h.length]="</tr>";return h;},renderBody:function(T,Q){var ao=this.cfg.getProperty(b.START_WEEKDAY.key);this.preMonthDays=T.getDay();if(ao>0){this.preMonthDays-=ao;}if(this.preMonthDays<0){this.preMonthDays+=7;}this.monthDays=d.findMonthEnd(T).getDate();this.postMonthDays=f.DISPLAY_DAYS-this.preMonthDays-this.monthDays;T=d.subtract(T,d.DAY,this.preMonthDays);var F,q,o="w",L="_cell",J="wd",Z="d",v,X,af=this.today,u=this.cfg,ae,D=af.getFullYear(),Y=af.getMonth(),k=af.getDate(),ad=u.getProperty(b.PAGEDATE.key),j=u.getProperty(b.HIDE_BLANK_WEEKS.key),P=u.getProperty(b.SHOW_WEEK_FOOTER.key),I=u.getProperty(b.SHOW_WEEK_HEADER.key),O=u.getProperty(b.OOM_SELECT.key),B=u.getProperty(b.MINDATE.key),H=u.getProperty(b.MAXDATE.key),A=this.Locale.YEAR_OFFSET;if(B){B=d.clearTime(B);}if(H){H=d.clearTime(H);}Q[Q.length]='<tbody class="m'+(ad.getMonth()+1)+" "+this.Style.CSS_BODY+'">';var am=0,w=document.createElement("div"),R=document.createElement("td");w.appendChild(R);var ac=this.parent||this;for(var ah=0;ah<6;ah++){F=d.getWeekNumber(T,ao);q=o+F;if(ah!==0&&j===true&&T.getMonth()!=ad.getMonth()){break;}else{Q[Q.length]='<tr class="'+q+'">';if(I){Q=this.renderRowHeader(F,Q);}for(var an=0;an<7;an++){v=[];this.clearElement(R);R.className=this.Style.CSS_CELL;R.id=this.id+L+am;if(T.getDate()==k&&T.getMonth()==Y&&T.getFullYear()==D){v[v.length]=ac.renderCellStyleToday;}var G=[T.getFullYear(),T.getMonth()+1,T.getDate()];this.cellDates[this.cellDates.length]=G;ae=T.getMonth()!=ad.getMonth();if(ae&&!O){v[v.length]=ac.renderCellNotThisMonth;}else{c.addClass(R,J+T.getDay());c.addClass(R,Z+T.getDate());var S=this.renderStack.concat();for(var ag=0,al=S.length;ag<al;++ag){X=null;var aa=S[ag],ap=aa[0],h,K,n;switch(ap){case f.DATE:h=aa[1][1];K=aa[1][2];n=aa[1][0];if(T.getMonth()+1==h&&T.getDate()==K&&T.getFullYear()==n){X=aa[2];this.renderStack.splice(ag,1);}break;case f.MONTH_DAY:h=aa[1][0];K=aa[1][1];if(T.getMonth()+1==h&&T.getDate()==K){X=aa[2];this.renderStack.splice(ag,1);}break;case f.RANGE:var N=aa[1][0],M=aa[1][1],U=N[1],z=N[2],E=N[0],ak=d.getDate(E,U-1,z),m=M[1],W=M[2],g=M[0],aj=d.getDate(g,m-1,W);if(T.getTime()>=ak.getTime()&&T.getTime()<=aj.getTime()){X=aa[2];if(T.getTime()==aj.getTime()){this.renderStack.splice(ag,1);
index d20ecf2..227ec8a 100644 (file)
@@ -1056,8 +1056,9 @@ YAHOO.widget.DateMath = {
 
     /**
      * Returns a new JavaScript Date object, representing the given year, month and date. Time fields (hr, min, sec, ms) on the new Date object
-     * are set to 0. The method allows Date instances to be created with the a year less than 100. "new Date(year, month, date)" implementations 
-     * set the year to 19xx if a year (xx) which is less than 100 is provided.
+     * are set to 0, except the hour which is set to 12 (noon) to avoid issues around the start of Daylight Savings Time. The method allows Date
+     * instances to be created with the a year less than 100. "new Date(year, month, date)" implementations set the year to 19xx if a year (xx)
+     * which is less than 100 is provided.
      * <p>
      * <em>NOTE:</em>Validation on argument values is not performed. It is the caller's responsibility to ensure
      * arguments are valid as per the ECMAScript-262 Date object specification for the new Date(year, month[, date]) constructor.
@@ -1074,13 +1075,13 @@ YAHOO.widget.DateMath = {
             d = 1;
         }
         if (y >= 100) {
-            dt = new Date(y, m, d);
+            dt = new Date(y, m, d, 12);
         } else {
             dt = new Date();
             dt.setFullYear(y);
             dt.setMonth(m);
             dt.setDate(d);
-            dt.setHours(0,0,0,0);
+            dt.setHours(12,0,0,0);
         }
         return dt;
     }
index 7566973..3940247 100644 (file)
@@ -3109,7 +3109,7 @@ class assign {
 
         $gradingmanager = get_grading_manager($this->get_context(), 'mod_assign', 'submissions');
 
-        $perpage = get_user_preferences('assign_perpage', 10);
+        $perpage = (int) get_user_preferences('assign_perpage', 10);
         $filter = get_user_preferences('assign_filter', '');
         $markerfilter = get_user_preferences('assign_markerfilter', '');
         $workflowfilter = get_user_preferences('assign_workflowfilter', '');
index 835de83..77f5567 100644 (file)
@@ -134,6 +134,9 @@ class mod_assign_mod_form extends moodleform_mod {
         $name = get_string('teamsubmission', 'assign');
         $mform->addElement('selectyesno', 'teamsubmission', $name);
         $mform->addHelpButton('teamsubmission', 'teamsubmission', 'assign');
+        if ($assignment->has_submissions_or_grades()) {
+            $mform->freeze('teamsubmission');
+        }
 
         $name = get_string('requireallteammemberssubmit', 'assign');
         $mform->addElement('selectyesno', 'requireallteammemberssubmit', $name);
index eb05d32..01c5365 100644 (file)
     echo $OUTPUT->header();
 
     $headingvalue = format_string($forum->name);
-    if (has_capability('mod/forum:viewdiscussion', $modcontext)) {
+    if ((!isguestuser() && isloggedin()) && has_capability('mod/forum:viewdiscussion', $modcontext)) {
         // Discussion subscription.
         if (\mod_forum\subscriptions::is_subscribable($forum)) {
             $headingvalue .= '&nbsp;';
index b3a63b1..aec5df1 100644 (file)
@@ -3717,7 +3717,7 @@ function forum_print_discussion_header(&$post, $forum, $group=-1, $datestring=""
           userdate($usedate, $datestring).'</a>';
     echo "</td>\n";
 
-    if (has_capability('mod/forum:viewdiscussion', $modcontext)) {
+    if ((!isguestuser() && isloggedin()) && has_capability('mod/forum:viewdiscussion', $modcontext)) {
         // Discussion subscription.
         if (\mod_forum\subscriptions::is_subscribable($forum)) {
             echo '<td class="discussionsubscription">';
@@ -5820,7 +5820,13 @@ function forum_print_recent_mod_activity($activity, $courseid, $detail, $modname
     echo $OUTPUT->user_picture($activity->user, array('courseid'=>$courseid));
     echo "</td><td class=\"$class\">";
 
-    echo '<div class="title">';
+    if ($activity->content->parent) {
+        $class = 'title';
+    } else {
+        // Bold the title of new discussions so they stand out.
+        $class = 'title bold';
+    }
+    echo "<div class=\"{$class}\">";
     if ($detail) {
         $aname = s($activity->name);
         echo "<img src=\"" . $OUTPUT->pix_url('icon', $activity->type) . "\" ".
index d05a83d..cfdacb8 100644 (file)
@@ -269,3 +269,38 @@ Feature: A user can control their own subscription preferences for a discussion
     And I follow "Test post subject two"
     And I follow "Reply"
     And the field "Discussion subscription" matches value "I don't want email copies of posts to this discussion"
+
+ Scenario: A guest should not be able to subscribe to a discussion
+   Given I click on "Home" "link" in the "Navigation" "block"
+   And I add a "Forum" to section "1" and I fill the form with:
+     | Forum name        | Test forum name |
+     | Forum type        | Standard forum for general use |
+     | Description       | Test forum description |
+   And I add a new discussion to "Test forum name" forum with:
+     | Subject | Test post subject one |
+     | Message | Test post message one |
+   And I log out
+   When I log in as "guest"
+   And I follow "Test forum name"
+   Then "Not subscribed. Click to subscribe." "link" should not exist in the "Test post subject one" "table_row"
+   And "You are subscribed to this discussion. Click to unsubscribe." "link" should not exist in the "Test post subject one" "table_row"
+   And I follow "Test post subject one"
+   And "Not subscribed. Click to subscribe." "link" should not exist
+   And "You are subscribed to this discussion. Click to unsubscribe." "link" should not exist
+
+ Scenario: A user who is not logged in should not be able to subscribe to a discussion
+   Given I click on "Home" "link" in the "Navigation" "block"
+   And I add a "Forum" to section "1" and I fill the form with:
+     | Forum name        | Test forum name |
+     | Forum type        | Standard forum for general use |
+     | Description       | Test forum description |
+   And I add a new discussion to "Test forum name" forum with:
+     | Subject | Test post subject one |
+     | Message | Test post message one |
+   And I log out
+   When I follow "Test forum name"
+   Then "Not subscribed. Click to subscribe." "link" should not exist in the "Test post subject one" "table_row"
+   And "You are subscribed to this discussion. Click to unsubscribe." "link" should not exist in the "Test post subject one" "table_row"
+   And I follow "Test post subject one"
+   And "Not subscribed. Click to subscribe." "link" should not exist
+   And "You are subscribed to this discussion. Click to unsubscribe." "link" should not exist
index 30367de..2ff5ef6 100644 (file)
@@ -190,6 +190,8 @@ class backup_lesson_activity_structure_step extends backup_activity_structure_st
         // Annotate the file areas in user by the lesson module.
         $lesson->annotate_files('mod_lesson', 'mediafile', null);
         $page->annotate_files('mod_lesson', 'page_contents', 'id');
+        $answer->annotate_files('mod_lesson', 'page_answers', 'id');
+        $answer->annotate_files('mod_lesson', 'page_responses', 'id');
 
         // Prepare and return the structure we have just created for the lesson module.
         return $this->prepare_activity_structure($lesson);
index 4b8351c..3dbbc90 100644 (file)
@@ -55,6 +55,7 @@ class restore_lesson_activity_task extends restore_activity_task {
         $contents = array();
 
         $contents[] = new restore_decode_content('lesson_pages', array('contents'), 'lesson_page');
+        $contents[] = new restore_decode_content('lesson_answers', array('answer', 'response'), 'lesson_answer');
 
         return $contents;
     }
index a06adb5..34e8371 100644 (file)
@@ -105,7 +105,7 @@ class restore_lesson_activity_structure_step extends restore_activity_structure_
 
         // Set a dummy mapping to get the old ID so that it can be used by get_old_parentid when
         // processing attempts. It will be corrected in after_execute
-        $this->set_mapping('lesson_answer', $data->id, 0);
+        $this->set_mapping('lesson_answer', $data->id, 0, true); // Has related fileareas.
 
         // Answers need to be processed in order, so we store them in an
         // instance variable and insert them in the after_execute stage
@@ -186,7 +186,7 @@ class restore_lesson_activity_structure_step extends restore_activity_structure_
         ksort($this->answers);
         foreach ($this->answers as $answer) {
             $newitemid = $DB->insert_record('lesson_answers', $answer);
-            $this->set_mapping('lesson_answer', $answer->id, $newitemid);
+            $this->set_mapping('lesson_answer', $answer->id, $newitemid, true);
 
             // Update the lesson attempts to use the newly created answerid
             $DB->set_field('lesson_attempts', 'answerid', $newitemid, array(
@@ -199,6 +199,8 @@ class restore_lesson_activity_structure_step extends restore_activity_structure_
         $this->add_related_files('mod_lesson', 'mediafile', null);
         // Add lesson page files, by lesson_page itemname
         $this->add_related_files('mod_lesson', 'page_contents', 'lesson_page');
+        $this->add_related_files('mod_lesson', 'page_answers', 'lesson_answer');
+        $this->add_related_files('mod_lesson', 'page_responses', 'lesson_answer');
 
         // Remap all the restored prevpageid and nextpageid now that we have all the pages and their mappings
         $rs = $DB->get_recordset('lesson_pages', array('lessonid' => $this->task->get_activityid()),
index e61107c..786ab33 100644 (file)
@@ -85,6 +85,31 @@ if ($edit) {
     $data->id = $cm->id;
     $editoroptions['context'] = $context;
     $data = file_prepare_standard_editor($data, 'contents', $editoroptions, $context, 'mod_lesson', 'page_contents',  $editpage->id);
+
+    $answerscount = 0;
+    $answers = $editpage->get_answers();
+    foreach ($answers as $answer) {
+        $answereditor = 'answer_editor['.$answerscount.']';
+        if (is_array($data->$answereditor)) {
+            $answerdata = $data->$answereditor;
+            $answerdraftid = file_get_submitted_draft_itemid($answereditor);
+            $answertext = file_prepare_draft_area($answerdraftid, $PAGE->cm->context->id,
+                    'mod_lesson', 'page_answers', $answer->id, $editoroptions, $answerdata['text']);
+            $data->$answereditor = array('text' => $answertext, 'format' => $answerdata['format'], 'itemid' => $answerdraftid);
+        }
+
+        $responseeditor = 'response_editor['.$answerscount.']';
+        if (is_array($data->$responseeditor)) {
+            $responsedata = $data->$responseeditor;
+            $responsedraftid = file_get_submitted_draft_itemid($responseeditor);
+            $responsetext = file_prepare_draft_area($responsedraftid, $PAGE->cm->context->id,
+                    'mod_lesson', 'page_responses', $answer->id, $editoroptions, $responsedata['text']);
+            $data->$responseeditor = array('text' => $responsetext, 'format' => $responsedata['format'],
+                    'itemid' => $responsedraftid);
+        }
+        $answerscount++;
+    }
+
     $mform->set_data($data);
     $PAGE->navbar->add(get_string('edit'), new moodle_url('/mod/lesson/edit.php', array('id'=>$id)));
     $PAGE->navbar->add(get_string('editingquestionpage', 'lesson', get_string($mform->qtypestring, 'lesson')));
index 81fd75c..594554f 100644 (file)
@@ -336,7 +336,9 @@ $string['page'] = 'Page: {$a}';
 $string['page-mod-lesson-x'] = 'Any lesson page';
 $string['page-mod-lesson-view'] = 'View or preview lesson page';
 $string['page-mod-lesson-edit'] = 'Edit lesson page';
+$string['pageanswers'] = 'Page answers';
 $string['pagecontents'] = 'Page contents';
+$string['pageresponses'] = 'Page responses';
 $string['pages'] = 'Pages';
 $string['pagetitle'] = 'Page title';
 $string['password'] = 'Password';
index e21101d..f83a6e5 100644 (file)
@@ -865,6 +865,13 @@ function lesson_pluginfile($course, $cm, $context, $filearea, $args, $forcedownl
         }
         $fullpath = "/$context->id/mod_lesson/$filearea/$pageid/".implode('/', $args);
 
+    } else if ($filearea === 'page_answers' || $filearea === 'page_responses') {
+        $itemid = (int)array_shift($args);
+        if (!$pageanswers = $DB->get_record('lesson_answers', array('id' => $itemid))) {
+            return false;
+        }
+        $fullpath = "/$context->id/mod_lesson/$filearea/$itemid/".implode('/', $args);
+
     } else if ($filearea === 'mediafile') {
         if (count($args) > 1) {
             // Remove the itemid when it appears to be part of the arguments. If there is only one argument
@@ -897,6 +904,8 @@ function lesson_get_file_areas() {
     $areas = array();
     $areas['page_contents'] = get_string('pagecontents', 'mod_lesson');
     $areas['mediafile'] = get_string('mediafile', 'mod_lesson');
+    $areas['page_answers'] = get_string('pageanswers', 'mod_lesson');
+    $areas['page_responses'] = get_string('pageresponses', 'mod_lesson');
     return $areas;
 }
 
index 9517df2..1d77395 100644 (file)
@@ -790,8 +790,19 @@ abstract class lesson_add_page_form_base extends moodleform {
         if ($label === null) {
             $label = get_string('answer', 'lesson');
         }
-        $this->_form->addElement('editor', 'answer_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
-        $this->_form->setDefault('answer_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE));
+
+        if ($this->qtype != 'multichoice' && $this->qtype != 'matching') {
+            $this->_form->addElement('editor', 'answer_editor['.$count.']', $label,
+                    array('rows' => '4', 'columns' => '80'), array('noclean' => true));
+            $this->_form->setDefault('answer_editor['.$count.']', array('text' => '', 'format' => FORMAT_MOODLE));
+        } else {
+            $this->_form->addElement('editor', 'answer_editor['.$count.']', $label,
+                    array('rows' => '4', 'columns' => '80'),
+                    array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $this->_customdata['maxbytes']));
+            $this->_form->setType('answer_editor['.$count.']', PARAM_RAW);
+            $this->_form->setDefault('answer_editor['.$count.']', array('text' => '', 'format' => FORMAT_HTML));
+        }
+
         if ($required) {
             $this->_form->addRule('answer_editor['.$count.']', get_string('required'), 'required', null, 'client');
         }
@@ -808,8 +819,12 @@ abstract class lesson_add_page_form_base extends moodleform {
         if ($label === null) {
             $label = get_string('response', 'lesson');
         }
-        $this->_form->addElement('editor', 'response_editor['.$count.']', $label, array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
-        $this->_form->setDefault('response_editor['.$count.']', array('text'=>'', 'format'=>FORMAT_MOODLE));
+        $this->_form->addElement('editor', 'response_editor['.$count.']', $label,
+                 array('rows' => '4', 'columns' => '80'),
+                 array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $this->_customdata['maxbytes']));
+        $this->_form->setType('response_editor['.$count.']', PARAM_RAW);
+        $this->_form->setDefault('response_editor['.$count.']', array('text' => '', 'format' => FORMAT_HTML));
+
         if ($required) {
             $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client');
         }
@@ -1861,6 +1876,8 @@ abstract class lesson_page extends lesson_base {
         $context = context_module::instance($cm->id);
         $fs = get_file_storage();
         $fs->delete_area_files($context->id, 'mod_lesson', 'page_contents', $this->properties->id);
+        $fs->delete_area_files($context->id, 'mod_lesson', 'page_answers', $this->properties->id);
+        $fs->delete_area_files($context->id, 'mod_lesson', 'page_responses', $this->properties->id);
 
         // repair the hole in the linkage
         if (!$this->properties->prevpageid && !$this->properties->nextpageid) {
@@ -1958,7 +1975,7 @@ abstract class lesson_page extends lesson_base {
      * @return stdClass Returns the result of the attempt
      */
     final public function record_attempt($context) {
-        global $DB, $USER, $OUTPUT;
+        global $DB, $USER, $OUTPUT, $PAGE;
 
         /**
          * This should be overridden by each page type to actually check the response
@@ -2064,6 +2081,9 @@ abstract class lesson_page extends lesson_base {
                     $options->noclean = true;
                     $options->para = true;
                     $options->overflowdiv = true;
+                    $result->response = file_rewrite_pluginfile_urls($result->response, 'pluginfile.php', $context->id,
+                            'mod_lesson', 'page_responses', $result->answerid);
+
                     $result->feedback = $OUTPUT->box(format_text($this->get_contents(), $this->properties->contentsformat, $options), 'generalbox boxaligncenter');
                     $result->feedback .= '<div class="correctanswer generalbox"><em>'.get_string("youranswer", "lesson").'</em> : '.$result->studentanswer; // already in clean html
                     $result->feedback .= $OUTPUT->box($result->response, $class); // already conerted to HTML
@@ -2146,6 +2166,51 @@ abstract class lesson_page extends lesson_base {
         return true;
     }
 
+    /**
+     * save editor answers files and update answer record
+     *
+     * @param object $context
+     * @param int $maxbytes
+     * @param object $answer
+     * @param object $answereditor
+     * @param object $responseeditor
+     */
+    public function save_answers_files($context, $maxbytes, &$answer, $answereditor = '', $responseeditor = '') {
+        global $DB;
+        if (isset($answereditor['itemid'])) {
+            $answer->answer = file_save_draft_area_files($answereditor['itemid'],
+                    $context->id, 'mod_lesson', 'page_answers', $answer->id,
+                    array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $maxbytes),
+                    $answer->answer, null);
+            $DB->set_field('lesson_answers', 'answer', $answer->answer, array('id' => $answer->id));
+        }
+        if (isset($responseeditor['itemid'])) {
+            $answer->response = file_save_draft_area_files($responseeditor['itemid'],
+                    $context->id, 'mod_lesson', 'page_responses', $answer->id,
+                    array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $maxbytes),
+                    $answer->response, null);
+            $DB->set_field('lesson_answers', 'response', $answer->response, array('id' => $answer->id));
+        }
+    }
+
+    /**
+     * Rewrite urls in answer and response of a question answer
+     *
+     * @param object $answer
+     * @return object answer with rewritten urls
+     */
+    public static function rewrite_answers_urls($answer) {
+        global $PAGE;
+
+        $context = context_module::instance($PAGE->cm->id);
+        $answer->answer = file_rewrite_pluginfile_urls($answer->answer, 'pluginfile.php', $context->id,
+                'mod_lesson', 'page_answers', $answer->id);
+        $answer->response = file_rewrite_pluginfile_urls($answer->response, 'pluginfile.php', $context->id,
+                'mod_lesson', 'page_responses', $answer->id);
+
+        return $answer;
+    }
+
     /**
      * Updates a lesson page and its answers within the database
      *
@@ -2201,6 +2266,10 @@ abstract class lesson_page extends lesson_base {
                     $DB->update_record("lesson_answers", $this->answers[$i]->properties());
                 }
 
+                // Save files in answers and responses.
+                $this->save_answers_files($context, $maxbytes, $this->answers[$i],
+                        $properties->answer_editor[$i], $properties->response_editor[$i]);
+
             } else if (isset($this->answers[$i]->id)) {
                 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id));
                 unset($this->answers[$i]);
@@ -2260,13 +2329,16 @@ abstract class lesson_page extends lesson_base {
      * @return array
      */
     public function create_answers($properties) {
-        global $DB;
+        global $DB, $PAGE;
         // now add the answers
         $newanswer = new stdClass;
         $newanswer->lessonid = $this->lesson->id;
         $newanswer->pageid = $this->properties->id;
         $newanswer->timecreated = $this->properties->timecreated;
 
+        $cm = get_coursemodule_from_instance('lesson', $this->lesson->id, $this->lesson->course);
+        $context = context_module::instance($cm->id);
+
         $answers = array();
 
         for ($i = 0; $i < $this->lesson->maxanswers; $i++) {
@@ -2289,6 +2361,13 @@ abstract class lesson_page extends lesson_base {
                     $answer->score = $properties->score[$i];
                 }
                 $answer->id = $DB->insert_record("lesson_answers", $answer);
+                if (isset($properties->response_editor[$i])) {
+                    $this->save_answers_files($context, $PAGE->course->maxbytes, $answer,
+                            $properties->answer_editor[$i], $properties->response_editor[$i]);
+                } else {
+                    $this->save_answers_files($context, $PAGE->course->maxbytes, $answer,
+                            $properties->answer_editor[$i]);
+                }
                 $answers[$answer->id] = new lesson_page_answer($answer);
             } else {
                 break;
index ea0f0f4..1897188 100644 (file)
@@ -96,13 +96,16 @@ class lesson_page_type_matching extends lesson_page {
     }
 
     public function create_answers($properties) {
-        global $DB;
+        global $DB, $PAGE;
         // now add the answers
         $newanswer = new stdClass;
         $newanswer->lessonid = $this->lesson->id;
         $newanswer->pageid = $this->properties->id;
         $newanswer->timecreated = $this->properties->timecreated;
 
+        $cm = get_coursemodule_from_instance('lesson', $this->lesson->id, $this->lesson->course);
+        $context = context_module::instance($cm->id);
+
         $answers = array();
 
         // need to add two to offset correct response and wrong response
@@ -127,6 +130,8 @@ class lesson_page_type_matching extends lesson_page {
 
             if (isset($answer->answer) && $answer->answer != '') {
                 $answer->id = $DB->insert_record("lesson_answers", $answer);
+                $this->save_answers_files($context, $PAGE->course->maxbytes,
+                        $answer, $properties->answer_editor[$i]);
                 $answers[$answer->id] = new lesson_page_answer($answer);
             } else if ($i < 2) {
                 $answer->id = $DB->insert_record("lesson_answers", $answer);
@@ -159,6 +164,9 @@ class lesson_page_type_matching extends lesson_page {
 
         $response = $data->response;
         $getanswers = $this->get_answers();
+        foreach ($getanswers as $key => $answer) {
+            $getanswers[$key] = parent::rewrite_answers_urls($answer);
+        }
 
         $correct = array_shift($getanswers);
         $wrong   = array_shift($getanswers);
@@ -333,6 +341,9 @@ class lesson_page_type_matching extends lesson_page {
                 } else {
                     $DB->update_record("lesson_answers", $this->answers[$i]->properties());
                 }
+                // Save files in answers and responses.
+                $this->save_answers_files($context, $maxbytes, $this->answers[$i],
+                        $properties->answer_editor[$i], $properties->response_editor[$i]);
             } else if ($i < 2) {
                 if (!isset($this->answers[$i]->id)) {
                     $this->answers[$i]->id =  $DB->insert_record("lesson_answers", $this->answers[$i]);
@@ -340,6 +351,9 @@ class lesson_page_type_matching extends lesson_page {
                     $DB->update_record("lesson_answers", $this->answers[$i]->properties());
                 }
 
+                // Save files in answers and responses.
+                $this->save_answers_files( $context, $maxbytes, $this->answers[$i],
+                        $properties->answer_editor[$i], $properties->response_editor[$i]);
             } else if (isset($this->answers[$i]->id)) {
                 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id));
                 unset($this->answers[$i]);
@@ -460,12 +474,21 @@ class lesson_add_page_form_matching extends lesson_add_page_form_base {
     public function custom_definition() {
 
         $this->_form->addElement('header', 'correctresponse', get_string('correctresponse', 'lesson'));
-        $this->_form->addElement('editor', 'answer_editor[0]', get_string('correctresponse', 'lesson'), array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
+        $this->_form->addElement('editor', 'answer_editor[0]', get_string('correctresponse', 'lesson'),
+                array('rows' => '4', 'columns' => '80'),
+                array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $this->_customdata['maxbytes']));
+        $this->_form->setType('answer_editor[0]', PARAM_RAW);
+        $this->_form->setDefault('answer_editor[0]', array('text' => '', 'format' => FORMAT_HTML));
         $this->add_jumpto(0, get_string('correctanswerjump','lesson'), LESSON_NEXTPAGE);
         $this->add_score(0, get_string("correctanswerscore", "lesson"), 1);
 
         $this->_form->addElement('header', 'wrongresponse', get_string('wrongresponse', 'lesson'));
-        $this->_form->addElement('editor', 'answer_editor[1]', get_string('wrongresponse', 'lesson'), array('rows'=>'4', 'columns'=>'80'), array('noclean'=>true));
+        $this->_form->addElement('editor', 'answer_editor[1]', get_string('wrongresponse', 'lesson'),
+                array('rows' => '4', 'columns' => '80'),
+                array('noclean' => true, 'maxfiles' => EDITOR_UNLIMITED_FILES, 'maxbytes' => $this->_customdata['maxbytes']));
+        $this->_form->setType('answer_editor[1]', PARAM_RAW);
+        $this->_form->setDefault('answer_editor[1]', array('text' => '', 'format' => FORMAT_HTML));
+
         $this->add_jumpto(1, get_string('wronganswerjump','lesson'), LESSON_THISPAGE);
         $this->add_score(1, get_string("wronganswerscore", "lesson"), 0);
 
@@ -488,7 +511,7 @@ class lesson_add_page_form_matching extends lesson_add_page_form_base {
 class lesson_display_answer_form_matching extends moodleform {
 
     public function definition() {
-        global $USER, $OUTPUT;
+        global $USER, $OUTPUT, $PAGE;
         $mform = $this->_form;
         $answers = $this->_customdata['answers'];
         $useranswers = $this->_customdata['useranswers'];
@@ -529,6 +552,9 @@ class lesson_display_answer_form_matching extends moodleform {
                     // Temporary fixed until MDL-38885 gets integrated
                     $mform->setType('response', PARAM_TEXT);
                 }
+                $context = context_module::instance($PAGE->cm->id);
+                $answer->answer = file_rewrite_pluginfile_urls($answer->answer, 'pluginfile.php', $context->id,
+                        'mod_lesson', 'page_answers', $answer->id);
                 $mform->addElement('select', $responseid, format_text($answer->answer,$answer->answerformat,$options), $responseoptions, $disabled);
                 $mform->setType($responseid, PARAM_TEXT);
                 if ($hasattempt) {
index 8d8409f..99cbe08 100644 (file)
@@ -77,6 +77,8 @@ class lesson_page_type_multichoice extends lesson_page {
         foreach ($answers as $key=>$answer) {
             if ($answer->answer === '') {
                 unset($answers[$key]);
+            } else {
+                $answers[$key] = parent::rewrite_answers_urls($answer);
             }
         }
         return $answers;
@@ -246,6 +248,7 @@ class lesson_page_type_multichoice extends lesson_page {
             if (!$answer = $DB->get_record("lesson_answers", array("id" => $result->answerid))) {
                 print_error("Continue: answer record not found");
             }
+            $answer = parent::rewrite_answers_urls($answer);
             if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) {
                 $result->correctanswer = true;
             }
index 7a8a0f4..d5584ee 100644 (file)
@@ -50,6 +50,9 @@ class lesson_page_type_truefalse extends lesson_page {
     public function display($renderer, $attempt) {
         global $USER, $CFG, $PAGE;
         $answers = $this->get_answers();
+        foreach ($answers as $key => $answer) {
+            $answers[$key] = parent::rewrite_answers_urls($answer);
+        }
         shuffle($answers);
 
         $params = array('answers'=>$answers, 'lessonid'=>$this->lesson->id, 'contents'=>$this->get_contents(), 'attempt'=>$attempt);
@@ -81,6 +84,7 @@ class lesson_page_type_truefalse extends lesson_page {
         }
         $result->answerid = $data->answerid;
         $answer = $DB->get_record("lesson_answers", array("id" => $result->answerid), '*', MUST_EXIST);
+        $answer = parent::rewrite_answers_urls($answer);
         if ($this->lesson->jumpto_is_correct($this->properties->id, $answer->jumpto)) {
             $result->correctanswer = true;
         }
@@ -104,6 +108,7 @@ class lesson_page_type_truefalse extends lesson_page {
         $options->para = false;
         $i = 1;
         foreach ($answers as $answer) {
+            $answer = parent::rewrite_answers_urls($answer);
             $cells = array();
             if ($this->lesson->custom && $answer->score > 0) {
                 // if the score is > 0, then it is correct
@@ -193,6 +198,9 @@ class lesson_page_type_truefalse extends lesson_page {
                 } else {
                     $DB->update_record("lesson_answers", $this->answers[$i]->properties());
                 }
+                // Save files in answers and responses.
+                $this->save_answers_files($context, $maxbytes, $this->answers[$i],
+                        $properties->answer_editor[$i], $properties->response_editor[$i]);
             } else if (isset($this->answers[$i]->id)) {
                 $DB->delete_records('lesson_answers', array('id'=>$this->answers[$i]->id));
                 unset($this->answers[$i]);
@@ -238,6 +246,7 @@ class lesson_page_type_truefalse extends lesson_page {
         $formattextdefoptions->para = false;
         $formattextdefoptions->noclean = true;
         foreach ($answers as $answer) {
+            $answer = parent::rewrite_answers_urls($answer);
             if ($this->properties->qoption) {
                 if ($useranswer == null) {
                     $userresponse = array();
@@ -385,6 +394,7 @@ class lesson_display_answer_form_truefalse extends moodleform {
                 $ansid = 'answer_id';
             }
 
+            $answer = lesson_page::rewrite_answers_urls($answer);
             $mform->addElement('radio', $ansid, null, format_text($answer->answer, $answer->answerformat, $options), $answer->id, $disabled);
             $mform->setType($ansid, PARAM_INT);
             if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) {
diff --git a/mod/lesson/tests/behat/questions_images.feature b/mod/lesson/tests/behat/questions_images.feature
new file mode 100644 (file)
index 0000000..3433d45
--- /dev/null
@@ -0,0 +1,97 @@
+@mod @mod_lesson
+Feature: In a lesson activity, teacher can add embedded images in questions answers and responses
+  As a teacher
+  I need to add questions with images in answers and responses
+
+  @javascript @_file_upload
+  Scenario: questions with images in answers and responses
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+      | student1 | Student | 1 | student1@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname | category |
+      | Course 1 | C1 | 0 |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+      | student1 | C1 | student |
+    And I log in as "teacher1"
+    And I navigate to "My private files" node in "My profile"
+    And I upload "mod/lesson/tests/fixtures/moodle_logo.jpg" file to "Files" filemanager
+    And I click on "Save changes" "button"
+    When I am on homepage
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Lesson" to section "1" and I fill the form with:
+      | Name | Test lesson name |
+    And I follow "Test lesson name"
+    And I follow "Add a question page"
+    And I set the field "Select a question type" to "Multichoice"
+    And I press "Add a question page"
+    And I set the following fields to these values:
+      | Page title | Multichoice question |
+      | Page contents | What animal is an amphibian? |
+      | id_answer_editor_0 | Frog |
+      | id_response_editor_0 | Correct answer |
+      | id_jumpto_0 | Next page |
+      | id_score_0 | 1 |
+      | id_answer_editor_1 | Cat |
+      | id_response_editor_1 | Incorrect answer |
+      | id_jumpto_1 | This page |
+      | id_score_1 | 0 |
+      | id_answer_editor_2 | Dog |
+      | id_response_editor_2 | Incorrect answer |
+      | id_jumpto_2 | This page |
+      | id_score_2 | 0 |
+    And I click on "Image" "button" in the "#fitem_id_answer_editor_2" "css_element"
+    And I click on "Browse repositories..." "button"
+    And I click on "Private files" "link"
+    And I click on "moodle_logo.jpg" "link"
+    And I click on "Select this file" "button"
+    And I set the field "Describe this image for someone who cannot see it" to "It's the logo"
+    And I click on "Save image" "button"
+    And I press "Save page"
+    And I set the field "qtype" to "Question"
+    And I set the field "Select a question type" to "True/false"
+    And I press "Add a question page"
+    And I set the following fields to these values:
+      | Page title | Next question |
+      | Page contents | Paper is made from trees. |
+      | id_answer_editor_0 | True |
+      | id_response_editor_0 | Correct |
+      | id_jumpto_0 | Next page |
+      | id_answer_editor_1 | False |
+      | id_response_editor_1 | Wrong |
+      | id_jumpto_1 | This page |
+    And I click on "Image" "button" in the "#fitem_id_response_editor_0" "css_element"
+    And I click on "Browse repositories..." "button"
+    And I click on "Private files" "link"
+    And I click on "moodle_logo.jpg" "link"
+    And I click on "Select this file" "button"
+    And I set the field "Describe this image for someone who cannot see it" to "It's the logo"
+    And I click on "Save image" "button"
+    And I press "Save page"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    When I follow "Test lesson name"
+    Then I should see "What animal is an amphibian?"
+    And "//img[contains(@src, 'pluginfile.php')]" "xpath_element" should exist in the ".answeroption" "css_element"
+    And "//img[contains(@src, 'moodle_logo.jpg')]" "xpath_element" should exist in the ".answeroption" "css_element"
+    And I set the following fields to these values:
+      | Cat | 1 |
+    And I press "Submit"
+    And I should see "Incorrect answer"
+    And I press "Continue"
+    And I should see "Paper is made from trees."
+    And I set the following fields to these values:
+      | True | 1 |
+    And I press "Submit"
+    And I should see "Correct"
+    And I should not see "Wrong"
+    And "//img[contains(@src, 'pluginfile.php')]" "xpath_element" should exist in the ".correctanswer" "css_element"
+    And "//img[contains(@src, 'moodle_logo.jpg')]" "xpath_element" should exist in the ".correctanswer" "css_element"
+    And I press "Continue"
+    And I should see "Congratulations - end of lesson reached"
+    And I should see "Your score is 1 (out of 2)."
diff --git a/mod/lesson/tests/fixtures/moodle_logo.jpg b/mod/lesson/tests/fixtures/moodle_logo.jpg
new file mode 100644 (file)
index 0000000..f2d5365
Binary files /dev/null and b/mod/lesson/tests/fixtures/moodle_logo.jpg differ
index 89873cb..a2a683a 100644 (file)
@@ -1,4 +1,4 @@
-@qtype @qformat_gift
+@qformat @qformat_gift
 Feature: Test importing questions from GIFT format.
   In order to reuse questions
   As an teacher
index 799f9ae..8221bef 100644 (file)
@@ -1,4 +1,4 @@
-@qtype @qformat_webct
+@qformat @qformat_webct
 Feature: Test importing questions from WebCT format.
   In order to reuse questions from am obsolete commercial LMS
   As an teacher
index f829536..4f6ee79 100644 (file)
@@ -1,4 +1,4 @@
-@qtype @qformat_xml
+@qformat @qformat_xml
 Feature: Test importing questions from Moodle XML format.
   In order to reuse questions
   As an teacher
index f066175..dd3aa62 100644 (file)
             }
         }
     }
-    
+
     .dir-rtl {
         .navbar {
             .nav-collapse.active {
index e0737b4..5d526a9 100644 (file)
@@ -691,7 +691,7 @@ if ($mode === MODE_USERDETAILS) {    // Print simple listing.
 
                 $links = array();
 
-                if ($CFG->bloglevel > 0) {
+                if ($CFG->enableblogs && $CFG->bloglevel > 0) {
                     $links[] = html_writer::link(new moodle_url('/blog/index.php?userid='.$user->id), get_string('blogs', 'blog'));
                 }
 
index 9952817..fe00e01 100644 (file)
@@ -29,7 +29,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2014092500.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2014092900.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.