Merge branch 'wip-MDL-35847-master' of git://github.com/phalacee/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 4 Feb 2013 23:08:44 +0000 (00:08 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Mon, 4 Feb 2013 23:08:44 +0000 (00:08 +0100)
43 files changed:
calendar/lib.php
course/lib.php
help.php
lang/en/question.php
lib/ajax/blocks.php
lib/navigationlib.php
lib/outputrequirementslib.php
lib/yui/blocks/blocks.js
lib/yui/notification/assets/skins/sam/notification.css [deleted file]
lib/yui/notification/notification.js
mod/assign/locallib.php
mod/assign/renderer.php
mod/assign/submission/comments/lib.php
mod/assign/submission/file/lib.php
mod/assign/submission/onlinetext/lib.php
mod/assign/tests/locallib_test.php
mod/assignment/lib.php
mod/scorm/datamodels/aicc.js.php
mod/scorm/datamodels/callback.js.php [deleted file]
mod/scorm/datamodels/scorm_12.js.php
mod/scorm/datamodels/scorm_13.js.php
mod/scorm/module.js
mod/workshop/allocation/scheduled/db/events.php [new file with mode: 0644]
mod/workshop/allocation/scheduled/lib.php
mod/workshop/allocation/scheduled/version.php
mod/workshop/assessment.php
mod/workshop/form/assessment_form.php
mod/workshop/lang/en/workshop.php
mod/workshop/locallib.php
mod/workshop/version.php
mod/workshop/view.php
question/engine/tests/helpers.php
question/type/edit_question_form.php
question/type/essay/question.php
question/type/essay/tests/helper.php [new file with mode: 0644]
question/type/essay/tests/walkthrough_test.php [new file with mode: 0644]
question/type/shortanswer/question.php
theme/base/pix/sprite.png [moved from lib/yui/notification/assets/skins/sam/sprite.png with 100% similarity]
theme/base/style/core.css
theme/base/style/question.css
theme/magazine/style/core.css
theme/mymobile/style/core.css
user/profile.php

index 654a5b9..fc8d32b 100644 (file)
@@ -798,7 +798,7 @@ function calendar_get_events_by_id($eventids) {
  * @return string $content return available control for the calender in html
  */
 function calendar_top_controls($type, $data) {
-    global $CFG;
+    global $CFG, $PAGE;
     $content = '';
     if(!isset($data['d'])) {
         $data['d'] = 1;
@@ -821,6 +821,7 @@ function calendar_top_controls($type, $data) {
 
     $data['m'] = $date['mon'];
     $data['y'] = $date['year'];
+    $urlbase = $PAGE->url;
 
     //Accessibility: calendar block controls, replaced <table> with <div>.
     //$nexttext = link_arrow_right(get_string('monthnext', 'access'), $url='', $accesshide=true);
@@ -830,8 +831,8 @@ function calendar_top_controls($type, $data) {
         case 'frontpage':
             list($prevmonth, $prevyear) = calendar_sub_month($data['m'], $data['y']);
             list($nextmonth, $nextyear) = calendar_add_month($data['m'], $data['y']);
-            $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), 'index.php?', 0, $nextmonth, $nextyear, $accesshide=true);
-            $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), 'index.php?', 0, $prevmonth, $prevyear, true);
+            $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, 0, $nextmonth, $nextyear, true);
+            $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, 0, $prevmonth, $prevyear, true);
 
             $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'month')), 1, $data['m'], $data['y']);
             if (!empty($data['id'])) {
@@ -857,8 +858,8 @@ function calendar_top_controls($type, $data) {
         case 'course':
             list($prevmonth, $prevyear) = calendar_sub_month($data['m'], $data['y']);
             list($nextmonth, $nextyear) = calendar_add_month($data['m'], $data['y']);
-            $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), 'view.php?id='.$data['id'].'&amp;', 0, $nextmonth, $nextyear, $accesshide=true);
-            $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), 'view.php?id='.$data['id'].'&amp;', 0, $prevmonth, $prevyear, true);
+            $nextlink = calendar_get_link_next(get_string('monthnext', 'access'), $urlbase, 0, $nextmonth, $nextyear, true);
+            $prevlink = calendar_get_link_previous(get_string('monthprev', 'access'), $urlbase, 0, $prevmonth, $prevyear, true);
 
             $calendarlink = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'month')), 1, $data['m'], $data['y']);
             if (!empty($data['id'])) {
index c5e9d86..be41f42 100644 (file)
@@ -3837,16 +3837,6 @@ function include_course_ajax($course, $usedmodules = array(), $enabledmodules =
             )), null, true);
     }
 
-    // Include blocks dragdrop
-    $params = array(
-        'courseid' => $course->id,
-        'pagetype' => $PAGE->pagetype,
-        'pagelayout' => $PAGE->pagelayout,
-        'subpage' => $PAGE->subpage,
-        'regions' => $PAGE->blocks->get_regions(),
-    );
-    $PAGE->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
-
     // Require various strings for the command toolbox
     $PAGE->requires->strings_for_js(array(
             'moveleft',
index 390b29e..6afdd97 100644 (file)
--- a/help.php
+++ b/help.php
@@ -67,7 +67,13 @@ if ($sm->string_exists($identifier.'_help', $component)) {
     $options->newlines = false;
     $options->overflowdiv = !$ajax;
 
-    echo $OUTPUT->heading(format_string(get_string($identifier, $component)), 1, 'helpheading');
+    if ($ajax) {
+        // When using AJAX, the header should be H2 as it is in the same DOM as the calling page.
+        echo $OUTPUT->heading(format_string(get_string($identifier, $component)), 2, 'helpheading');
+    } else {
+        // When not using AJAX, the header should be H1 as it is in it's own window.
+        echo $OUTPUT->heading(format_string(get_string($identifier, $component)), 1, 'helpheading');
+    }
     // Should be simple wiki only MDL-21695
     echo format_text(get_string($identifier.'_help', $component), FORMAT_MARKDOWN, $options);
 
index d7d58fe..540e9d1 100644 (file)
@@ -335,6 +335,7 @@ $string['generalfeedback_help'] = 'General feedback is shown to the student afte
 You can use the general feedback to give students a fully worked answer and perhaps a link to more information they can use if they did not understand the questions.';
 $string['hidden'] = 'Hidden';
 $string['hintn'] = 'Hint {no}';
+$string['hintnoptions'] = 'Hint {no} options';
 $string['hinttext'] = 'Hint text';
 $string['howquestionsbehave'] = 'How questions behave';
 $string['howquestionsbehave_help'] = 'Students can interact with the questions in the quiz in various different ways. For example, you may wish the students to enter an answer to each question and then submit the entire quiz, before anything is graded or they get any feedback. That would be \'Deferred feedback\' mode.
index 470106d..ab24525 100644 (file)
@@ -30,6 +30,7 @@ require_once(dirname(__FILE__) . '/../../config.php');
 $courseid = required_param('courseid', PARAM_INT);
 $pagelayout = required_param('pagelayout', PARAM_ALPHAEXT);
 $pagetype = required_param('pagetype', PARAM_ALPHAEXT);
+$contextid = required_param('contextid', PARAM_INT);
 $subpage = optional_param('subpage', '', PARAM_ALPHANUMEXT);
 $cmid = optional_param('cmid', null, PARAM_INT);
 $action = optional_param('action', '', PARAM_ALPHA);
@@ -50,9 +51,33 @@ if (!is_null($cmid)) {
 require_login($courseid, false, $cm);
 require_sesskey();
 
+// Set context from ID, so we don't have to guess it from other info.
+$PAGE->set_context(context::instance_by_id($contextid));
+
 // Setting layout to replicate blocks configuration for the page we edit
 $PAGE->set_pagelayout($pagelayout);
 $PAGE->set_subpage($subpage);
+$pagetype = explode('-', $pagetype);
+switch ($pagetype[0]) {
+    case 'my':
+        // My Home page needs to have 'content' block region set up.
+        $PAGE->set_blocks_editing_capability('moodle/my:manageblocks');
+        $PAGE->blocks->add_region('content');
+        break;
+    case 'user':
+        if ($pagelayout == 'mydashboard') {
+            // User profile pages also need the 'content' block region set up.
+            $PAGE->blocks->add_region('content');
+            // If it's not the current user's profile, we need a different capability.
+            if ($PAGE->context->contextlevel == CONTEXT_USER && $PAGE->context->instanceid != $USER->id) {
+                $PAGE->set_blocks_editing_capability('moodle/user:manageblocks');
+            } else {
+                $PAGE->set_blocks_editing_capability('moodle/user:manageownblocks');
+            }
+        }
+        break;
+}
+
 echo $OUTPUT->header(); // send headers
 
 switch ($action) {
index 185d960..b76433d 100644 (file)
@@ -195,8 +195,6 @@ class navigation_node implements renderable {
         if ($this->text === null) {
             throw new coding_exception('You must set the text for the node when you create it.');
         }
-        // Default the title to the text
-        $this->title = $this->text;
         // Instantiate a new navigation node collection for this nodes children
         $this->children = new navigation_node_collection();
     }
@@ -2157,8 +2155,7 @@ class global_navigation extends navigation_node {
             $usernode->add(get_string('messages', 'message'), $url, self::TYPE_SETTING, null, 'messages');
         }
 
-        $context = context_user::instance($USER->id);
-        if ($iscurrentuser && has_capability('moodle/user:manageownfiles', $context)) {
+        if ($iscurrentuser && has_capability('moodle/user:manageownfiles', context_user::instance($USER->id))) {
             $url = new moodle_url('/user/files.php');
             $usernode->add(get_string('myfiles'), $url, self::TYPE_SETTING);
         }
index d4eff1c..8c97eac 100644 (file)
@@ -282,6 +282,22 @@ class page_requirements_manager {
         if ($page->pagelayout === 'frametop') {
             $this->js_init_call('M.util.init_frametop');
         }
+
+        // Include block drag/drop if editing is on
+        if ($page->user_is_editing()) {
+            $params = array(
+                'courseid' => $page->course->id,
+                'pagetype' => $page->pagetype,
+                'pagelayout' => $page->pagelayout,
+                'subpage' => $page->subpage,
+                'regions' => $page->blocks->get_regions(),
+                'contextid' => $page->context->id,
+            );
+            if (!empty($page->cm->id)) {
+                $params['cmid'] = $page->cm->id;
+            }
+            $page->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
+        }
     }
 
     /**
index edb655f..baa06be 100644 (file)
@@ -10,7 +10,9 @@ YUI.add('moodle-core-blocks', function(Y) {
         LIGHTBOX : 'lightbox',
         REGIONCONTENT : 'region-content',
         SKIPBLOCK : 'skip-block',
-        SKIPBLOCKTO : 'skip-block-to'
+        SKIPBLOCKTO : 'skip-block-to',
+        MYINDEX : 'page-my-index',
+        REGIONMAIN : 'region-main'
     }
 
     var DRAGBLOCK = function() {
@@ -26,6 +28,15 @@ YUI.add('moodle-core-blocks', function(Y) {
             this.samenodeclass = CSS.BLOCK;
             this.parentnodeclass = CSS.REGIONCONTENT;
 
+            // Add relevant classes and ID to 'content' block region on My Home page.
+            var myhomecontent = Y.Node.all('body#'+CSS.MYINDEX+' #'+CSS.REGIONMAIN+' > .'+CSS.REGIONCONTENT);
+            if (myhomecontent.size() > 0) {
+                var contentregion = myhomecontent.item(0);
+                contentregion.addClass(CSS.BLOCKREGION);
+                contentregion.set('id', CSS.REGIONCONTENT);
+                contentregion.one('div').addClass(CSS.REGIONCONTENT);
+            }
+
             // Initialise blocks dragging
             // Find all block regions on the page
             var blockregionlist = Y.Node.all('div.'+CSS.BLOCKREGION);
@@ -42,17 +53,18 @@ YUI.add('moodle-core-blocks', function(Y) {
                 var regioncontent = Y.Node.create('<div></div>')
                     .addClass(CSS.REGIONCONTENT);
                 blockregion.appendChild(regioncontent);
+                var pre = blockregionlist.filter('#region-pre');
+                var post = blockregionlist.filter('#region-post');
 
-                var regionid = this.get_region_id(blockregionlist.item(0));
-                if (regionid === 'post') {
+                if (pre.size() === 0 && post.size() === 1) {
                     // pre block is missing, instert it before post
                     blockregion.setAttrs({id : 'region-pre'});
-                    blockregionlist.item(0).insert(blockregion, 'before');
+                    post.item(0).insert(blockregion, 'before');
                     blockregionlist.unshift(blockregion);
-                } else {
+                } else if (post.size() === 0 && pre.size() === 1) {
                     // post block is missing, instert it after pre
                     blockregion.setAttrs({id : 'region-post'});
-                    blockregionlist.item(0).insert(blockregion, 'after');
+                    pre.item(0).insert(blockregion, 'after');
                     blockregionlist.push(blockregion);
                 }
             }
@@ -214,6 +226,7 @@ YUI.add('moodle-core-blocks', function(Y) {
                 pagelayout : this.get('pagelayout'),
                 pagetype : this.get('pagetype'),
                 subpage : this.get('subpage'),
+                contextid : this.get('contextid'),
                 action : 'move',
                 bui_moveid : this.get_block_id(dragnode),
                 bui_newregion : this.get_block_region(dropnode)
@@ -263,6 +276,9 @@ YUI.add('moodle-core-blocks', function(Y) {
             cmid : {
                 value : null
             },
+            contextid : {
+                value : null
+            },
             pagelayout : {
                 value : null
             },
diff --git a/lib/yui/notification/assets/skins/sam/notification.css b/lib/yui/notification/assets/skins/sam/notification.css
deleted file mode 100644 (file)
index 91fd8d2..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-.moodle-dialogue-base .hidden,
-.moodle-dialogue-base .moodle-dialogue-hidden {display:none;}
-.moodle-dialogue-base .moodle-dialogue-lightbox {background-color:#AAA;}
-.moodle-dialogue-base .moodle-dialogue {background-color:#666;border:0 solid #666;border-right-width:3px;border-bottom-width:3px;}
-.moodle-dialogue-base .moodle-dialogue-wrap {background-color:#FFF;margin-top:-3px;margin-left:-3px;border:1px solid #555;height:auto;}
-.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd {font-size:110%;color:inherit;font-weight:bold;text-align:left;padding:5px 6px;margin:0;border-bottom:1px solid #ccc;background:#f6f6f6;}
-.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd h1{font-size:100%;font-weight:bold;margin:0;padding:0;display:inline;}
-.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd .yui3-widget-buttons {padding: 5px;}
-.moodle-dialogue-base .closebutton {background-image:url(sprite.png);width:25px;height:15px;background-repeat:no-repeat;float:right;vertical-align:middle;display:inline-block;cursor:pointer;padding:0px;border-style:none;}
-.moodle-dialogue-base .moodle-dialogue-bd {padding:5px; overflow: auto;}
-.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-content {background:#FFF;padding:0px;}
-.moodle-dialogue-base .moodle-dialogue .moodle-dialogue-content .moodle-dialogue-ft {padding:0px;}
-
-.moodle-dialogue-confirm .confirmation-dialogue {text-align:center;}
-.moodle-dialogue-confirm .confirmation-message {margin:0.5em 1em;}
-.moodle-dialogue-confirm .confirmation-dialogue input {min-width:80px;text-align:center;}
-
-.moodle-dialogue-exception .moodle-exception-message {text-align:center;margin:1em;}
-.moodle-dialogue-exception .moodle-exception-param {margin-bottom:0.5em;}
-.moodle-dialogue-exception .moodle-exception-param label {width:150px;font-weight:bold;}
-.moodle-dialogue-exception .param-stacktrace label {display:block;background-color:#EEE;margin:0;padding:4px 1em;border:1px solid #ccc;border-bottom-width:0;}
-.moodle-dialogue-exception .param-stacktrace pre {display:block;border:1px solid #ccc;background-color:#fff;height:200px;overflow:auto;}
-.moodle-dialogue-exception .param-stacktrace .stacktrace-file {color:navy;display:inline-block;font-size:80%;margin:4px 0;}
-.moodle-dialogue-exception .param-stacktrace .stacktrace-line {color:#AA0000;display:inline-block;font-size:80%;width:50px;margin:4px 1em;}
-.moodle-dialogue-exception .param-stacktrace .stacktrace-call {color:#333;font-size:90%;padding-left:25px;margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #eee;}
index 8969f6a..83d4f4e 100644 (file)
@@ -401,4 +401,4 @@ M.core.confirm = CONFIRM;
 M.core.exception = EXCEPTION;
 M.core.ajaxException = AJAXEXCEPTION;
 
-}, '@VERSION@', {requires:['base','node','panel','event-key', 'moodle-core-notification-skin', 'dd-plugin']});
+}, '@VERSION@', {requires:['base','node','panel','event-key', 'dd-plugin']});
index b418500..e28ba43 100644 (file)
@@ -1806,7 +1806,8 @@ class assign {
                 }
             }
             $grading_info = grade_get_grades($course->id, 'mod', 'assign', $cm->instance, $USER->id);
-            if (isset($grading_info->items[0]) && !$grading_info->items[0]->grades[$USER->id]->hidden ) {
+            if (isset($grading_info->items[0]->grades[$USER->id]) &&
+                    !$grading_info->items[0]->grades[$USER->id]->hidden ) {
                 $grade = $grading_info->items[0]->grades[$USER->id]->str_grade;
             } else {
                 $grade = '-';
@@ -2784,6 +2785,30 @@ class assign {
         return false;
     }
 
+    /**
+     * Perform an access check to see if the current $USER can view this group submission.
+     *
+     * @param int $groupid
+     * @return bool
+     */
+    public function can_view_group_submission($groupid) {
+        global $USER;
+
+        if (!is_enrolled($this->get_course_context(), $USER->id)) {
+            return false;
+        }
+        if (has_capability('mod/assign:grade', $this->context)) {
+            return true;
+        }
+        $members = $this->get_submission_group_members($groupid, true);
+        foreach ($members as $member) {
+            if ($member->id == $USER->id) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Perform an access check to see if the current $USER can view this users submission.
      *
@@ -3040,8 +3065,12 @@ class assign {
                                         $instance->id,
                                         $user->id);
 
-            $gradingitem = $gradinginfo->items[0];
-            $gradebookgrade = $gradingitem->grades[$user->id];
+            $gradingitem = null;
+            $gradebookgrade = null;
+            if (isset($gradinginfo->items[0])) {
+                $gradingitem = $gradinginfo->items[0];
+                $gradebookgrade = $gradingitem->grades[$user->id];
+            }
 
             // Check to see if all feedback plugins are empty.
             $emptyplugins = true;
@@ -3055,25 +3084,34 @@ class assign {
                 }
             }
 
-            if (!($gradebookgrade->hidden) && ($gradebookgrade->grade !== null || !$emptyplugins)) {
+            $cangrade = has_capability('mod/assign:grade', $this->get_context());
+            // If there is feedback or a visible grade, show the summary.
+            if ((!empty($gradebookgrade->grade) && ($cangrade || !$gradebookgrade->hidden)) ||
+                    !$emptyplugins) {
 
-                $gradefordisplay = '';
+                $gradefordisplay = null;
+                $gradeddate = null;
+                $grader = null;
                 $gradingmanager = get_grading_manager($this->get_context(), 'mod_assign', 'submissions');
 
-                if ($controller = $gradingmanager->get_active_controller()) {
-                    $controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
-                    $cangrade = has_capability('mod/assign:grade', $this->get_context());
-                    $gradefordisplay = $controller->render_grade($PAGE,
-                                                                 $grade->id,
-                                                                 $gradingitem,
-                                                                 $gradebookgrade->str_long_grade,
-                                                                 $cangrade);
-                } else {
-                    $gradefordisplay = $this->display_grade($gradebookgrade->grade, false);
+                // Only show the grade if it is not hidden in gradebook.
+                if (!empty($gradebookgrade->grade) && ($cangrade || !$gradebookgrade->hidden)) {
+                    if ($controller = $gradingmanager->get_active_controller()) {
+                        $controller->set_grade_range(make_grades_menu($this->get_instance()->grade));
+                        $gradefordisplay = $controller->render_grade($PAGE,
+                                                                     $grade->id,
+                                                                     $gradingitem,
+                                                                     $gradebookgrade->str_long_grade,
+                                                                     $cangrade);
+                    } else {
+                        $gradefordisplay = $this->display_grade($gradebookgrade->grade, false);
+                    }
+                    $gradeddate = $gradebookgrade->dategraded;
+                    if (isset($grade->grader)) {
+                        $grader = $DB->get_record('user', array('id'=>$grade->grader));
+                    }
                 }
 
-                $gradeddate = $gradebookgrade->dategraded;
-                $grader = $DB->get_record('user', array('id'=>$grade->grader));
 
                 $feedbackstatus = new assign_feedback_status($gradefordisplay,
                                                       $gradeddate,
@@ -3877,6 +3915,9 @@ class assign {
             $record->userid = $userid;
             if ($modified >= 0) {
                 $record->grade = unformat_float(optional_param('quickgrade_' . $record->userid, -1, PARAM_TEXT));
+            } else {
+                // This user was not in the grading table.
+                continue;
             }
             $record->lastmodified = $modified;
             $record->gradinginfo = grade_get_grades($this->get_course()->id,
@@ -4401,10 +4442,18 @@ class assign {
         if (has_all_capabilities($capabilitylist, $this->get_course_context())) {
             $urlparams = array('id'=>$this->get_course()->id);
             $url = new moodle_url('/grade/report/grader/index.php', $urlparams);
-            $usergrade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+            $usergrade = '-';
+            if (isset($gradinginfo->items[0]->grades[$userid]->str_grade)) {
+                $usergrade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+            }
             $gradestring = $this->get_renderer()->action_link($url, $usergrade);
         } else {
-            $gradestring = $gradinginfo->items[0]->grades[$userid]->str_grade;
+            $usergrade = '-';
+            if (isset($gradinginfo->items[0]->grades[$userid]) &&
+                    !$grading_info->items[0]->grades[$userid]->hidden) {
+                $usergrade = $gradinginfo->items[0]->grades[$userid]->str_grade;
+            }
+            $gradestring = $usergrade;
         }
         $name = get_string('currentgrade', 'assign') . ':' . $gradestring;
         $mform->addElement('static', 'finalgrade', $name);
index cbf7a56..181e353 100644 (file)
@@ -321,18 +321,20 @@ class mod_assign_renderer extends plugin_renderer_base {
         $t = new html_table();
 
         // Grade.
-        $row = new html_table_row();
-        $cell1 = new html_table_cell(get_string('grade'));
-        $cell2 = new html_table_cell($status->gradefordisplay);
-        $row->cells = array($cell1, $cell2);
-        $t->data[] = $row;
+        if (isset($status->gradefordisplay)) {
+            $row = new html_table_row();
+            $cell1 = new html_table_cell(get_string('grade'));
+            $cell2 = new html_table_cell($status->gradefordisplay);
+            $row->cells = array($cell1, $cell2);
+            $t->data[] = $row;
 
-        // Grade date.
-        $row = new html_table_row();
-        $cell1 = new html_table_cell(get_string('gradedon', 'assign'));
-        $cell2 = new html_table_cell(userdate($status->gradeddate));
-        $row->cells = array($cell1, $cell2);
-        $t->data[] = $row;
+            // Grade date.
+            $row = new html_table_row();
+            $cell1 = new html_table_cell(get_string('gradedon', 'assign'));
+            $cell2 = new html_table_cell(userdate($status->gradeddate));
+            $row->cells = array($cell1, $cell2);
+            $t->data[] = $row;
+        }
 
         if ($status->grader) {
             // Grader.
index 5844463..5509350 100644 (file)
@@ -92,21 +92,15 @@ function assignsubmission_comments_comment_permissions(stdClass $options) {
     if ($assignment->get_instance()->id != $submission->assignment) {
         throw new comment_exception('invalidcontext');
     }
-    if (!has_capability('mod/assign:grade', $context)) {
-        if (!has_capability('mod/assign:submit', $context)) {
-            return array('post' => false, 'view' => false);
-        } else if ($assignment->get_instance()->teamsubmission) {
-            $group = $assignment->get_submission_group($USER->id);
-            $groupid = 0;
-            if ($group) {
-                $groupid = $group->id;
-            }
-            if ($groupid != $submission->groupid) {
-                return array('post' => false, 'view' => false);
-            }
-        } else if ($submission->userid != $USER->id) {
-            return array('post' => false, 'view' => false);
-        }
+
+    if ($assignment->get_instance()->teamsubmission &&
+        !$assignment->can_view_group_submission($submission->groupid)) {
+        return array('post' => false, 'view' => false);
+    }
+
+    if (!$assignment->get_instance()->teamsubmission &&
+        !$assignment->can_view_submission($submission->userid)) {
+        return array('post' => false, 'view' => false);
     }
 
     return array('post' => true, 'view' => true);
index 8b58fe2..c8fcbae 100644 (file)
@@ -40,7 +40,7 @@ function assignsubmission_file_pluginfile($course,
                                           $filearea,
                                           $args,
                                           $forcedownload) {
-    global $USER, $DB;
+    global $DB, $CFG;
 
     if ($context->contextlevel != CONTEXT_MODULE) {
         return false;
@@ -50,20 +50,26 @@ function assignsubmission_file_pluginfile($course,
     $itemid = (int)array_shift($args);
     $record = $DB->get_record('assign_submission',
                               array('id'=>$itemid),
-                              'userid, assignment',
+                              'userid, assignment, groupid',
                               MUST_EXIST);
     $userid = $record->userid;
+    $groupid = $record->groupid;
 
-    if (!$assign = $DB->get_record('assign', array('id'=>$cm->instance))) {
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+    $assign = new assign($context, $cm, $course);
+
+    if ($assign->get_instance()->id != $record->assignment) {
         return false;
     }
 
-    if ($assign->id != $record->assignment) {
+    if ($assign->get_instance()->teamsubmission &&
+        !$assign->can_view_group_submission($groupid)) {
         return false;
     }
 
-    // Check if this is the current users submission or the user has grading permission.
-    if ($USER->id != $userid and !has_capability('mod/assign:grade', $context)) {
+    if (!$assign->get_instance()->teamsubmission &&
+        !$assign->can_view_submission($userid)) {
         return false;
     }
 
@@ -72,7 +78,7 @@ function assignsubmission_file_pluginfile($course,
     $fullpath = "/{$context->id}/assignsubmission_file/$filearea/$itemid/$relativepath";
 
     $fs = get_file_storage();
-    if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+    if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) {
         return false;
     }
 
index 19e8e73..a2bcde9 100644 (file)
@@ -35,7 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * @return bool false if file not found, does not return if found - just send the file
  */
 function assignsubmission_onlinetext_pluginfile($course, $cm, context $context, $filearea, $args, $forcedownload) {
-    global $USER, $DB;
+    global $DB, $CFG;
 
     if ($context->contextlevel != CONTEXT_MODULE) {
         return false;
@@ -43,19 +43,28 @@ function assignsubmission_onlinetext_pluginfile($course, $cm, context $context,
 
     require_login($course, false, $cm);
     $itemid = (int)array_shift($args);
-    $record = $DB->get_record('assign_submission', array('id'=>$itemid), 'userid, assignment', MUST_EXIST);
+    $record = $DB->get_record('assign_submission',
+                              array('id'=>$itemid),
+                              'userid, assignment, groupid',
+                              MUST_EXIST);
     $userid = $record->userid;
+    $groupid = $record->groupid;
 
-    if (!$assign = $DB->get_record('assign', array('id'=>$cm->instance))) {
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+    $assign = new assign($context, $cm, $course);
+
+    if ($assign->get_instance()->id != $record->assignment) {
         return false;
     }
 
-    if ($assign->id != $record->assignment) {
+    if ($assign->get_instance()->teamsubmission &&
+        !$assign->can_view_group_submission($groupid)) {
         return false;
     }
 
-    // Check is users submission or has grading permission.
-    if ($USER->id != $userid and !has_capability('mod/assign:grade', $context)) {
+    if (!$assign->get_instance()->teamsubmission &&
+        !$assign->can_view_submission($userid)) {
         return false;
     }
 
@@ -64,7 +73,7 @@ function assignsubmission_onlinetext_pluginfile($course, $cm, context $context,
     $fullpath = "/{$context->id}/assignsubmission_onlinetext/$filearea/$itemid/$relativepath";
 
     $fs = get_file_storage();
-    if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
+    if (!($file = $fs->get_file_by_hash(sha1($fullpath))) || $file->is_directory()) {
         return false;
     }
 
index a9b8ab2..6f533b8 100644 (file)
@@ -658,6 +658,63 @@ class mod_assign_locallib_testcase extends advanced_testcase {
         }
     }
 
+    public function test_show_student_summary() {
+        global $CFG;
+
+        $this->setUser($this->editingteachers[0]);
+        $assign = $this->create_instance();
+
+        // No feedback should be available because this student has not been graded.
+        $this->setUser($this->students[0]);
+        $output = $assign->view_student_summary($this->students[0], true);
+        $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if there is no grade');
+        // Simulate adding a grade.
+        $this->setUser($this->teachers[0]);
+        $data = new stdClass();
+        $data->grade = '50.0';
+        $assign->testable_apply_grade_to_user($data, $this->students[0]->id);
+
+        // Now we should see the feedback
+        $this->setUser($this->students[0]);
+        $output = $assign->view_student_summary($this->students[0], true);
+        $this->assertNotEquals(false, strpos($output, 'Feedback'), 'Show feedback if there is a grade');
+
+        // Now hide the grade in gradebook.
+        $this->setUser($this->teachers[0]);
+        require_once($CFG->libdir.'/gradelib.php');
+        $gradeitem = new grade_item(array(
+            'itemtype'      => 'mod',
+            'itemmodule'    => 'assign',
+            'iteminstance'  => $assign->get_instance()->id,
+            'courseid'      => $this->course->id));
+
+        $gradeitem->set_hidden(1, false);
+
+        // No feedback should be available because the grade is hidden.
+        $this->setUser($this->students[0]);
+        $output = $assign->view_student_summary($this->students[0], true);
+        $this->assertEquals(false, strpos($output, 'Feedback'), 'Do not show feedback if the grade is hidden in the gradebook');
+
+        // Do the same but add feedback
+        $assign = $this->create_instance(array('assignfeedback_comments_enabled' => 1));
+
+        $this->setUser($this->teachers[0]);
+        $grade = $assign->get_user_grade($this->students[0]->id, true);
+        $data = new stdClass();
+        $data->assignfeedbackcomments_editor = array('text'=>'Tomato sauce',
+                                         'format'=>FORMAT_MOODLE);
+        $plugin = $assign->get_feedback_plugin_by_type('comments');
+        $plugin->save($grade, $data);
+
+        // Should have feedback but no grade
+        $this->setUser($this->students[0]);
+        $output = $assign->view_student_summary($this->students[0], true);
+        $this->assertNotEquals(false, strpos($output, 'Tomato sauce'), 'Show feedback even if there is no grade');
+        $this->assertEquals(false, strpos($output, 'Grade'), 'Do not show grade when there is no grade.');
+        $this->assertEquals(false, strpos($output, 'Graded on'), 'Do not show graded date when there is no grade.');
+    }
+
+
 }
 
 /**
index 132281c..7b9f9aa 100644 (file)
@@ -3574,12 +3574,15 @@ function assignment_get_all_submissions($assignment, $sort="", $dir="DESC") {
     if ($assignment->course == SITEID) {
         $select = '';
     }*/
-
+    $context = context_module::instance($assignment->id);
+    list($enroledsql, $params) = get_enrolled_sql($context, 'mod/assignment:submit');
+    $params['assignmentid'] = $assignment->id;
     return $DB->get_records_sql("SELECT a.*
-                                   FROM {assignment_submissions} a, {user} u
+                                    FROM {assignment_submissions} a
+                                    INNER JOIN (". $enroledsql .") u ON u.id = a.userid
                                   WHERE u.id = a.userid
-                                        AND a.assignment = ?
-                               ORDER BY $sort", array($assignment->id));
+                                        AND a.assignment = :assignmentid
+                                  ORDER BY $sort", $params);
 
 }
 
index a5dd434..1a55f6b 100644 (file)
@@ -219,13 +219,6 @@ if ($count > 0) {
         return "false";
     }
 
-
-<?php
-// pull in the TOC callback
-require_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php');
-?>
-
-
     function LMSFinish (param) {
         errorCode = "0";
         if (param == "") {
@@ -245,8 +238,8 @@ require_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php');
                 }
                 // trigger TOC update
                 var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
-                var callback = this.connectPrereqCallback;
-                YUI.use('yui2-connection', function(Y) {
+                var callback = M.mod_scorm.connectPrereqCallback;
+                YUI().use('yui2-connection', function(Y) {
                     Y.YUI2.util.Connect.asyncRequest('GET', sURL, callback, null);
                 });
                 return "true";
diff --git a/mod/scorm/datamodels/callback.js.php b/mod/scorm/datamodels/callback.js.php
deleted file mode 100644 (file)
index a51fc44..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
-
-?>
-   this.connectPrereqCallback = {
-
-        success: function(o) {
-            YUI.use('yui2-treeview', 'yui2-layout', function(Y) {
-                scorm_tree_node = Y.YUI2.widget.TreeView.getTree('scorm_tree');
-                if (o.responseText !== undefined) {
-                    //alert('got a response: ' + o.responseText);
-                    if (scorm_tree_node && o.responseText) {
-                        var hnode = scorm_tree_node.getHighlightedNode();
-                        var hidx = null;
-                        if (hnode) {
-                            hidx = hnode.index + scorm_tree_node.getNodeCount();
-                        }
-                        // all gone
-                        var root_node = scorm_tree_node.getRoot();
-                        while (root_node.children.length > 0) {
-                            scorm_tree_node.removeNode(root_node.children[0]);
-                        }
-                    }
-                    // make sure the temporary tree element is not there
-                    var el_old_tree = document.getElementById('scormtree123');
-                    if (el_old_tree) {
-                        el_old_tree.parentNode.removeChild(el_old_tree);
-                    }
-                    var el_new_tree = document.createElement('div');
-                    var pagecontent = document.getElementById("page-content");
-                    el_new_tree.setAttribute('id','scormtree123');
-                    el_new_tree.innerHTML = o.responseText;
-                    // make sure it doesnt show
-                    el_new_tree.style.display = 'none';
-                    pagecontent.appendChild(el_new_tree)
-                    // ignore the first level element as this is the title
-                    var startNode = el_new_tree.firstChild.firstChild;
-                    if (startNode.tagName == 'LI') {
-                        // go back to the beginning
-                        startNode = el_new_tree;
-                    }
-                    //var sXML = new XMLSerializer().serializeToString(startNode);
-                    scorm_tree_node.buildTreeFromMarkup('scormtree123');
-                    var el = document.getElementById('scormtree123');
-                    el.parentNode.removeChild(el);
-                    scorm_tree_node.expandAll();
-                    scorm_tree_node.render();
-                    if (hidx != null) {
-                        hnode = scorm_tree_node.getNodeByIndex(hidx);
-                        if (hnode) {
-                            hnode.highlight();
-                            scorm_layout_widget = Y.YUI2.widget.Layout.getLayoutById('scorm_layout');
-                            var left = scorm_layout_widget.getUnitByPosition('left');
-                            if (left.expanded) {
-                                hnode.focus();
-                            }
-                        }
-                    }
-                }
-            });
-        },
-
-        failure: function(o) {
-            // do some sort of error handling
-            var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
-            //TODO: Enable this error handing correctly - avoiding issues when closing player MDL-23470 
-            //alert('Prerequisites update failed - must restart SCORM player');
-            //window.location.href = sURL;
-        }
-
-    };
-
-
index f8b6963..d931282 100644 (file)
@@ -198,11 +198,6 @@ function SCORMapi1_2() {
         return "false";
     }
 
-<?php
-    // pull in the TOC callback
-    require_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php');
-?>
-
     function LMSFinish (param) {
         errorCode = "0";
         if (param == "") {
@@ -235,8 +230,8 @@ function SCORMapi1_2() {
                 ?>
                 // trigger TOC update
                 var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
-                var callback = this.connectPrereqCallback;
-                YUI.use('yui2-connection', function(Y) {
+                var callback = M.mod_scorm.connectPrereqCallback;
+                YUI().use('yui2-connection', function(Y) {
                     Y.YUI2.util.Connect.asyncRequest('GET', sURL, callback, null);
                 });
                 return result;
@@ -432,6 +427,12 @@ function SCORMapi1_2() {
         if (param == "") {
             if (Initialized) {
                 result = StoreData(cmi,false);
+                // trigger TOC update
+                var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
+                var callback = M.mod_scorm.connectPrereqCallback;
+                YUI().use('yui2-connection', function(Y) {
+                    Y.YUI2.util.Connect.asyncRequest('GET', sURL, callback, null);
+                });
                 <?php
                     if (scorm_debugging($scorm)) {
                         echo 'LogAPICall("Commit", param, "", 0);';
index a4ad5db..73bc453 100644 (file)
@@ -313,13 +313,6 @@ function SCORMapi1_3() {
         return "false";
     }
 
-
-<?php
-    // pull in the TOC callback
-    include_once($CFG->dirroot.'/mod/scorm/datamodels/callback.js.php');
- ?>
-
-
     function Terminate (param) {
         errorCode = "0";
         if (param == "") {
@@ -366,8 +359,8 @@ function SCORMapi1_3() {
                     }
                     // trigger TOC update
                     var sURL = "<?php echo $CFG->wwwroot; ?>" + "/mod/scorm/prereqs.php?a=<?php echo $scorm->id ?>&scoid=<?php echo $scoid ?>&attempt=<?php echo $attempt ?>&mode=<?php echo $mode ?>&currentorg=<?php echo $currentorg ?>&sesskey=<?php echo sesskey(); ?>";
-                    var callback = this.connectPrereqCallback;
-                    YUI.use('yui2-connection', function(Y) {
+                    var callback = M.mod_scorm.connectPrereqCallback;
+                    YUI().use('yui2-connection', function(Y) {
                         Y.YUI2.util.Connect.asyncRequest('GET', sURL, callback, null);
                     });
                 } else {
index 2ed708f..03902fa 100644 (file)
@@ -14,7 +14,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Javascript helper function for IMS Content Package module.
+ * Javascript helper function for SCORM module.
  *
  * @package   mod-scorm
  * @copyright 2009 Petr Skoda (http://skodak.org)
@@ -541,4 +541,86 @@ M.mod_scorm.init = function(Y, hide_nav, hide_toc, toc_title, window_name, launc
             scorm_resize_layout(true);
         };
     });
+};
+
+M.mod_scorm.connectPrereqCallback = {
+
+    success: function(o) {
+        YUI().use('yui2-treeview', 'yui2-layout', function(Y) {
+            // MDL-29159 The core version of getContentHtml doesn't escape text properly.
+            Y.YUI2.widget.TextNode.prototype.getContentHtml = function() {
+                var sb = [];
+                sb[sb.length] = this.href ? '<a' : '<span';
+                sb[sb.length] = ' id="' + Y.YUI2.lang.escapeHTML(this.labelElId) + '"';
+                sb[sb.length] = ' class="' + Y.YUI2.lang.escapeHTML(this.labelStyle) + '"';
+                if (this.href) {
+                    sb[sb.length] = ' href="' + Y.YUI2.lang.escapeHTML(this.href) + '"';
+                    sb[sb.length] = ' target="' + Y.YUI2.lang.escapeHTML(this.target) + '"';
+                }
+                if (this.title) {
+                    sb[sb.length] = ' title="' + Y.YUI2.lang.escapeHTML(this.title) + '"';
+                }
+                sb[sb.length] = ' >';
+                sb[sb.length] = this.label;
+                sb[sb.length] = this.href?'</a>':'</span>';
+                return sb.join("");
+            };
+
+            if (o.responseText !== undefined) {
+                var tree = new Y.YUI2.widget.TreeView('scorm_tree');
+                if (scorm_tree_node && o.responseText) {
+                    var hnode = scorm_tree_node.getHighlightedNode();
+                    var hidx = null;
+                    if (hnode) {
+                        hidx = hnode.index + scorm_tree_node.getNodeCount();
+                    }
+                    // all gone
+                    var root_node = scorm_tree_node.getRoot();
+                    while (root_node.children.length > 0) {
+                        scorm_tree_node.removeNode(root_node.children[0]);
+                    }
+                }
+                // make sure the temporary tree element is not there
+                var el_old_tree = document.getElementById('scormtree123');
+                if (el_old_tree) {
+                    el_old_tree.parentNode.removeChild(el_old_tree);
+                }
+                var el_new_tree = document.createElement('div');
+                var pagecontent = document.getElementById("page-content");
+                el_new_tree.setAttribute('id','scormtree123');
+                el_new_tree.innerHTML = o.responseText;
+                // make sure it doesnt show
+                el_new_tree.style.display = 'none';
+                pagecontent.appendChild(el_new_tree)
+                // ignore the first level element as this is the title
+                var startNode = el_new_tree.firstChild.firstChild;
+                if (startNode.tagName == 'LI') {
+                    // go back to the beginning
+                    startNode = el_new_tree;
+                }
+                //var sXML = new XMLSerializer().serializeToString(startNode);
+                scorm_tree_node.buildTreeFromMarkup('scormtree123');
+                var el = document.getElementById('scormtree123');
+                el.parentNode.removeChild(el);
+                scorm_tree_node.expandAll();
+                scorm_tree_node.render();
+                if (hidx != null) {
+                    hnode = scorm_tree_node.getNodeByIndex(hidx);
+                    if (hnode) {
+                        hnode.highlight();
+                        scorm_layout_widget = Y.YUI2.widget.Layout.getLayoutById('scorm_layout');
+                        var left = scorm_layout_widget.getUnitByPosition('left');
+                        if (left.expanded) {
+                            hnode.focus();
+                        }
+                    }
+                }
+            }
+        });
+    },
+
+    failure: function(o) {
+        // TODO: do some sort of error handling.
+    }
+
 };
\ No newline at end of file
diff --git a/mod/workshop/allocation/scheduled/db/events.php b/mod/workshop/allocation/scheduled/db/events.php
new file mode 100644 (file)
index 0000000..d9137fc
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Defines event handlers
+ *
+ * @package     workshopallocation_scheduled
+ * @subpackage  mod_workshop
+ * @category    event
+ * @copyright   2013 David Mudrak <david@moodle.com>
+ * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$handlers = array(
+
+    // The workshop main page is displayed to the user
+    'workshop_viewed' => array(
+        'handlerfile'       => '/mod/workshop/allocation/scheduled/lib.php',
+        'handlerfunction'   => 'workshopallocation_scheduled_workshop_viewed',
+        'schedule'          => 'instant',
+        'internal'          => 1,
+    ),
+
+);
index 11095a9..8809e93 100644 (file)
@@ -285,3 +285,50 @@ function workshopallocation_scheduled_cron() {
         // todo inform the teachers about the results
     }
 }
+
+////////////////////////////////////////////////////////////////////////////////
+// Events API
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Handler for the 'workshop_viewed' event
+ *
+ * This does the same job as {@link workshopallocation_scheduled_cron()} but for the
+ * single workshop. The idea is that we do not need to wait forcron to execute.
+ * Displaying the workshop main view.php can trigger the scheduled allocation, too.
+ *
+ * @param stdClass $event event data
+ * @return bool
+ */
+function workshopallocation_scheduled_workshop_viewed($event) {
+    global $DB;
+
+    $workshop = $event->workshop;
+    $now = time();
+
+    // Non-expensive check to see if the scheduled allocation can even happen.
+    if ($workshop->phase == workshop::PHASE_SUBMISSION and $workshop->submissionend > 0 and $workshop->submissionend < $now) {
+
+        // Make sure the scheduled allocation has been configured for this workshop, that it has not
+        // been executed yet and that the passed workshop record is still valid.
+        $sql = "SELECT a.id
+                  FROM {workshopallocation_scheduled} a
+                  JOIN {workshop} w ON a.workshopid = w.id
+                 WHERE w.id = :workshopid
+                       AND a.enabled = 1
+                       AND w.phase = :phase
+                       AND w.submissionend > 0
+                       AND w.submissionend < :now
+                       AND (a.timeallocated IS NULL OR a.timeallocated < w.submissionend)";
+        $params = array('workshopid' => $workshop->id, 'phase' => workshop::PHASE_SUBMISSION, 'now' => $now);
+
+        if ($DB->record_exists_sql($sql, $params)) {
+            // Allocate submissions for assessments.
+            $allocator = $workshop->allocator_instance('scheduled');
+            $result = $allocator->execute();
+            // todo inform the teachers about the results
+        }
+    }
+
+    return true;
+}
index 9bb53ce..ed8a3a5 100644 (file)
@@ -27,8 +27,8 @@
 defined('MOODLE_INTERNAL') || die();
 
 $plugin->component  = 'workshopallocation_scheduled';
-$plugin->version    = 2012112900;
-$plugin->requires   = 2012112900;
+$plugin->version    = 2013013100;
+$plugin->requires   = 2013012500;
 $plugin->dependencies = array(
     'workshopallocation_random'  => 2012112900,
 );
index 851f290..64cbf3f 100644 (file)
@@ -128,9 +128,15 @@ $strategy = $workshop->grading_strategy_instance();
 if (is_null($assessment->grade) and !$assessmenteditable) {
     $mform = null;
 } else {
+    // Are there any other pending assessments to do but this one?
+    if ($assessmenteditable) {
+        $pending = $workshop->get_pending_assessments_by_reviewer($assessment->reviewerid, $assessment->id);
+    } else {
+        $pending = array();
+    }
     // load the assessment form and process the submitted data eventually
     $mform = $strategy->get_assessment_form($PAGE->url, 'assessment', $assessment, $assessmenteditable,
-                                        array('editableweight' => $cansetassessmentweight));
+                                        array('editableweight' => $cansetassessmentweight, 'pending' => !empty($pending)));
     $mform->set_data(array('weight' => $assessment->weight)); // other values are set by subplugins
     if ($mform->is_cancelled()) {
         redirect($workshop->view_url());
@@ -146,6 +152,13 @@ if (is_null($assessment->grade) and !$assessmenteditable) {
         }
         if (!is_null($rawgrade) and isset($data->saveandclose)) {
             redirect($workshop->view_url());
+        } else if (!is_null($rawgrade) and isset($data->saveandshownext)) {
+            $next = reset($pending);
+            if (!empty($next)) {
+                redirect($workshop->assess_url($next->id));
+            } else {
+                redirect($PAGE->url); // This should never happen but just in case...
+            }
         } else {
             // either it is not possible to calculate the $rawgrade
             // or the reviewer has chosen "Save and continue"
index f6e5e03..43cd3fc 100644 (file)
@@ -77,8 +77,11 @@ class workshop_assessment_form extends moodleform {
             $buttonarray[] = $mform->createElement('cancel', 'backtoeditform', get_string('backtoeditform', 'workshop'));
         }
         if ($this->mode == 'assessment') {
-            $buttonarray[] = $mform->createElement('submit', 'saveandcontinue', get_string('saveandcontinue', 'workshop'));
+            if (!empty($this->options['pending'])) {
+                $buttonarray[] = $mform->createElement('submit', 'saveandshownext', get_string('saveandshownext', 'workshop'));
+            }
             $buttonarray[] = $mform->createElement('submit', 'saveandclose', get_string('saveandclose', 'workshop'));
+            $buttonarray[] = $mform->createElement('submit', 'saveandcontinue', get_string('saveandcontinue', 'workshop'));
             $buttonarray[] = $mform->createElement('cancel');
         }
         $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
index 5e1d515..25a4fbb 100644 (file)
@@ -208,6 +208,7 @@ $string['recentsubmissions'] = 'Workshop submissions:';
 $string['saveandclose'] = 'Save and close';
 $string['saveandcontinue'] = 'Save and continue editing';
 $string['saveandpreview'] = 'Save and preview';
+$string['saveandshownext'] = 'Save and show next';
 $string['selfassessmentdisabled'] = 'Self-assessment disabled';
 $string['showingperpage'] = 'Showing {$a} items per page';
 $string['showingperpagechange'] = 'Change ...';
index a534f4c..3d77819 100644 (file)
@@ -1169,6 +1169,37 @@ class workshop {
         return $DB->get_records_sql($sql, $params);
     }
 
+    /**
+     * Get allocated assessments not graded yet by the given reviewer
+     *
+     * @see self::get_assessments_by_reviewer()
+     * @param int $reviewerid the reviewer id
+     * @param null|int|array $exclude optional assessment id (or list of them) to be excluded
+     * @return array
+     */
+    public function get_pending_assessments_by_reviewer($reviewerid, $exclude = null) {
+
+        $assessments = $this->get_assessments_by_reviewer($reviewerid);
+
+        foreach ($assessments as $id => $assessment) {
+            if (!is_null($assessment->grade)) {
+                unset($assessments[$id]);
+                continue;
+            }
+            if (!empty($exclude)) {
+                if (is_array($exclude) and in_array($id, $exclude)) {
+                    unset($assessments[$id]);
+                    continue;
+                } else if ($id == $exclude) {
+                    unset($assessments[$id]);
+                    continue;
+                }
+            }
+        }
+
+        return $assessments;
+    }
+
     /**
      * Allocate a submission to a user for review
      *
index e442c13..c3983fe 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012112900;        // the current module version (YYYYMMDDXX)
-$module->requires  = 2012112900;        // requires this Moodle version
+$module->version   = 2013013100;        // the current module version (YYYYMMDDXX)
+$module->requires  = 2013012500;        // requires this Moodle version
 $module->component = 'mod_workshop';    // full name of the plugin (used for diagnostics)
 $module->cron      = 60;                // give as a chance every minute
index fbcbc46..37168ce 100644 (file)
@@ -60,6 +60,24 @@ $workshop->log('view');
 $completion = new completion_info($course);
 $completion->set_module_viewed($cm);
 
+// Fire the event
+events_trigger('workshop_viewed', (object)array(
+    'workshop' => $workshop,
+    'user' => $USER,
+));
+
+// If the phase is to be switched, do it asap. This just has to happen after triggering
+// the event so that the scheduled allocator had a chance to allocate submissions.
+if ($workshop->phase == workshop::PHASE_SUBMISSION and $workshop->phaseswitchassessment
+        and $workshop->submissionend > 0 and $workshop->submissionend < time()) {
+    $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
+    $workshop->log('update switch phase', $workshop->view_url(), $workshop->phase);
+    // Disable the automatic switching now so that it is not executed again by accident
+    // if the teacher changes the phase back to the submission one.
+    $DB->set_field('workshop', 'phaseswitchassessment', 0, array('id' => $workshop->id));
+    $workshop->phaseswitchassessment = 0;
+}
+
 if (!is_null($editmode) && $PAGE->user_allowed_editing()) {
     $USER->editing = $editmode;
 }
index cc8fbfe..494dbc8 100644 (file)
@@ -619,8 +619,14 @@ abstract class qbehaviour_walkthrough_test_base extends question_testcase {
     protected $displayoptions;
     /** @var question_usage_by_activity */
     protected $quba;
-    /** @var unknown_type integer */
+    /** @var integer */
+
     protected $slot;
+    /**
+     * @var string after {@link render()} has been called, this contains the
+     * display of the question in its current state.
+     */
+    protected $currentoutput = '';
 
     protected function setUp() {
         parent::setUp();
@@ -670,6 +676,14 @@ abstract class qbehaviour_walkthrough_test_base extends question_testcase {
         }
     }
 
+    /**
+     * Generate the HTML rendering of the question in its current state in
+     * $this->currentoutput so that it can be verified.
+     */
+    protected function render() {
+        $this->currentoutput = $this->quba->render_question($this->slot, $this->displayoptions);
+    }
+
     /**
      * @param $condition one or more Expectations. (users varargs).
      */
index 1af551b..e364c98 100644 (file)
@@ -371,24 +371,36 @@ abstract class question_edit_form extends question_wizard_form {
         }
     }
 
+    /**
+     * Create the form elements required by one hint.
+     * @param string $withclearwrong whether this quesiton type uses the 'Clear wrong' option on hints.
+     * @param string $withshownumpartscorrect whether this quesiton type uses the 'Show num parts correct' option on hints.
+     * @return array form field elements for one hint.
+     */
     protected function get_hint_fields($withclearwrong = false, $withshownumpartscorrect = false) {
         $mform = $this->_form;
 
+        $repeatedoptions = array();
         $repeated = array();
-        $repeated[] = $mform->createElement('header', 'hinthdr', get_string('hintn', 'question'));
-        $repeated[] = $mform->createElement('editor', 'hint', get_string('hinttext', 'question'),
+        $repeated[] = $mform->createElement('editor', 'hint', get_string('hintn', 'question'),
                 array('rows' => 5), $this->editoroptions);
         $repeatedoptions['hint']['type'] = PARAM_RAW;
 
+        $optionelements = array();
         if ($withclearwrong) {
-            $repeated[] = $mform->createElement('advcheckbox', 'hintclearwrong',
+            $optionelements[] = $mform->createElement('advcheckbox', 'hintclearwrong',
                     get_string('options', 'question'), get_string('clearwrongparts', 'question'));
         }
         if ($withshownumpartscorrect) {
-            $repeated[] = $mform->createElement('advcheckbox', 'hintshownumcorrect', '',
+            $optionelements[] = $mform->createElement('advcheckbox', 'hintshownumcorrect', '',
                     get_string('shownumpartscorrect', 'question'));
         }
 
+        if (count($optionelements)) {
+            $repeated[] = $mform->createElement('group', 'hintoptions',
+                 get_string('hintnoptions', 'question'), $optionelements, null, false);
+        }
+
         return array($repeated, $repeatedoptions);
     }
 
@@ -437,7 +449,7 @@ abstract class question_edit_form extends question_wizard_form {
         list($repeated, $repeatedoptions) = $this->get_hint_fields(
                 $withclearwrong, $withshownumpartscorrect);
         $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions,
-                'numhints', 'addhint', 1, get_string('addanotherhint', 'question'));
+                'numhints', 'addhint', 1, get_string('addanotherhint', 'question'), true);
     }
 
     public function set_data($question) {
index fa0ed9b..270c65b 100644 (file)
@@ -56,8 +56,10 @@ class qtype_essay_question extends question_with_responses {
     public function get_expected_data() {
         if ($this->responseformat == 'editorfilepicker') {
             $expecteddata = array('answer' => question_attempt::PARAM_CLEANHTML_FILES);
-        } else {
+        } else if ($this->responseformat == 'editor') {
             $expecteddata = array('answer' => PARAM_CLEANHTML);
+        } else {
+            $expecteddata = array('answer' => PARAM_RAW);
         }
         $expecteddata['answerformat'] = PARAM_ALPHANUMEXT;
         if ($this->attachments != 0) {
diff --git a/question/type/essay/tests/helper.php b/question/type/essay/tests/helper.php
new file mode 100644 (file)
index 0000000..e7484aa
--- /dev/null
@@ -0,0 +1,100 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Test helpers for the essay question type.
+ *
+ * @package    qtype_essay
+ * @copyright  2013 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+
+/**
+ * Test helper class for the essay question type.
+ *
+ * @copyright  2013 The Open University
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qtype_essay_test_helper extends question_test_helper {
+    public function get_test_questions() {
+        return array('editor', 'editorfilepicker', 'plain', 'monospaced');
+    }
+
+    /**
+     * Helper method to reduce duplication.
+     * @return qtype_essay_question
+     */
+    protected function initialise_essay_question() {
+        question_bank::load_question_definition_classes('essay');
+        $q = new qtype_essay_question();
+        test_question_maker::initialise_a_question($q);
+        $q->name = 'Essay question (HTML editor)';
+        $q->questiontext = 'Please write a story about a frog.';
+        $q->generalfeedback = 'I hope your story had a beginning, a middle and an end.';
+        $q->responseformat = 'editor';
+        $q->responsefieldlines = 10;
+        $q->attachments = 0;
+        $q->graderinfo = '';
+        $q->graderinfoformat = FORMAT_HTML;
+        $q->qtype = question_bank::get_qtype('essay');
+
+        return $q;
+    }
+
+    /**
+     * Makes an essay question using the HTML editor as input.
+     * @return qtype_essay_question
+     */
+    public function make_essay_question_editor() {
+        return $this->initialise_essay_question();
+    }
+
+    /**
+     * Makes an essay question using the HTML editor allowing embedded files as
+     * input, and up to three attachments.
+     * @return qtype_essay_question
+     */
+    public function make_essay_question_editorfilepicker() {
+        $q = $this->initialise_essay_question();
+        $q->responseformat = 'editorfilepicker';
+        $q->attachments = 3;
+        return $q;
+    }
+
+    /**
+     * Makes an essay question using plain text input.
+     * @return qtype_essay_question
+     */
+    public function make_essay_question_plain() {
+        $q = $this->initialise_essay_question();
+        $q->responseformat = 'plain';
+        return $q;
+    }
+
+    /**
+     * Makes an essay question using monospaced input.
+     * @return qtype_essay_question
+     */
+    public function make_essay_question_monospaced() {
+        $q = $this->initialise_essay_question();
+        $q->responseformat = 'monospaced';
+        return $q;
+    }
+}
diff --git a/question/type/essay/tests/walkthrough_test.php b/question/type/essay/tests/walkthrough_test.php
new file mode 100644 (file)
index 0000000..301edd3
--- /dev/null
@@ -0,0 +1,156 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains tests that walks essay questions through some attempts.
+ *
+ * @package   qtype_essay
+ * @copyright 2013 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
+
+
+/**
+ * Unit tests for the essay question type.
+ *
+ * @copyright 2013 The Open University
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class qtype_essay_walkthrough_test extends qbehaviour_walkthrough_test_base {
+
+    protected function check_contains_textarea($name, $content = '', $height = 10) {
+        $fieldname = $this->quba->get_field_prefix($this->slot) . $name;
+
+        $this->assertTag(array('tag' => 'textarea',
+                'attributes' => array('cols' => '60', 'rows' => $height,
+                        'name' => $fieldname)),
+                $this->currentoutput);
+
+        if ($content) {
+            $this->assertRegExp('/' . preg_quote(s($content), '/') . '/', $this->currentoutput);
+        }
+    }
+
+    public function test_deferred_feedback_html_editor() {
+
+        // Create a matching question.
+        $q = test_question_maker::make_question('essay', 'editor');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
+
+        $prefix = $this->quba->get_field_prefix($this->slot);
+        $fieldname = $prefix . 'answer';
+        $response = '<p>The <b>cat</b> sat on the mat. Then it ate a <b>frog</b>.</p>';
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->render();
+        $this->check_contains_textarea('answer', '');
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_does_not_contain_feedback_expectation());
+        $this->check_step_count(1);
+
+        // Save a response.
+        $this->quba->process_all_actions(null, array(
+            'slots'                    => $this->slot,
+            $fieldname                 => $response,
+            $fieldname . 'format'      => FORMAT_HTML,
+            $prefix . ':sequencecheck' => '1',
+        ));
+
+        // Verify.
+        $this->check_current_state(question_state::$complete);
+        $this->check_current_mark(null);
+        $this->check_step_count(2);
+        $this->render();
+        $this->check_contains_textarea('answer', $response);
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_does_not_contain_feedback_expectation());
+        $this->check_step_count(2);
+
+        // Finish the attempt.
+        $this->quba->finish_all_questions();
+
+        // Verify.
+        $this->check_current_state(question_state::$needsgrading);
+        $this->check_current_mark(null);
+        $this->render();
+        $this->assertRegExp('/' . preg_quote($response, '/') . '/', $this->currentoutput);
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_contains_general_feedback_expectation($q));
+    }
+
+    public function test_deferred_feedback_plain_text() {
+
+        // Create a matching question.
+        $q = test_question_maker::make_question('essay', 'plain');
+        $this->start_attempt_at_question($q, 'deferredfeedback', 1);
+
+        $prefix = $this->quba->get_field_prefix($this->slot);
+        $fieldname = $prefix . 'answer';
+        $response = "x < 1\nx > 0\nFrog & Toad were friends.";
+
+        // Check the initial state.
+        $this->check_current_state(question_state::$todo);
+        $this->check_current_mark(null);
+        $this->render();
+        $this->check_contains_textarea('answer', '');
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_does_not_contain_feedback_expectation());
+        $this->check_step_count(1);
+
+        // Save a response.
+        $this->quba->process_all_actions(null, array(
+            'slots'                    => $this->slot,
+            $fieldname                 => $response,
+            $fieldname . 'format'      => FORMAT_HTML,
+            $prefix . ':sequencecheck' => '1',
+        ));
+
+        // Verify.
+        $this->check_current_state(question_state::$complete);
+        $this->check_current_mark(null);
+        $this->check_step_count(2);
+        $this->render();
+        $this->check_contains_textarea('answer', $response);
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_does_not_contain_feedback_expectation());
+        $this->check_step_count(2);
+
+        // Finish the attempt.
+        $this->quba->finish_all_questions();
+
+        // Verify.
+        $this->check_current_state(question_state::$needsgrading);
+        $this->check_current_mark(null);
+        $this->render();
+        $this->assertRegExp('/' . preg_quote(s($response), '/') . '/', $this->currentoutput);
+        $this->check_current_output(
+                $this->get_contains_question_text_expectation($q),
+                $this->get_contains_general_feedback_expectation($q));
+    }
+}
index cb3c8a4..ba1dfc7 100644 (file)
@@ -87,6 +87,11 @@ class qtype_shortanswer_question extends question_graded_by_strategy
     }
 
     public static function compare_string_with_wildcard($string, $pattern, $ignorecase) {
+
+        // Normalise any non-canonical UTF-8 characters before we start.
+        $pattern = self::safe_normalize($pattern);
+        $string = self::safe_normalize($string);
+
         // Break the string on non-escaped asterisks.
         $bits = preg_split('/(?<!\\\\)\*/', $pattern);
         // Escape regexp special characters in the bits.
@@ -102,12 +107,32 @@ class qtype_shortanswer_question extends question_graded_by_strategy
             $regexp .= 'i';
         }
 
-        if (function_exists('normalizer_normalize')) {
-            $regexp = normalizer_normalize($regexp, Normalizer::FORM_C);
-            $string = normalizer_normalize($string, Normalizer::FORM_C);
+        return preg_match($regexp, trim($string));
+    }
+
+    /**
+     * Normalise a UTf-8 string to FORM_C, avoiding the pitfalls in PHP's
+     * normalizer_normalize function.
+     * @param string $string the input string.
+     * @return string the normalised string.
+     */
+    protected static function safe_normalize($string) {
+        if (!$string) {
+            return '';
         }
 
-        return preg_match($regexp, trim($string));
+        if (!function_exists('normalizer_normalize')) {
+            return $string;
+        }
+
+        $normalised = normalizer_normalize($string, Normalizer::FORM_C);
+        if (!$normalised) {
+            // An error occurred in normalizer_normalize, but we have no idea what.
+            debugging('Failed to normalise string: ' . $string, DEBUG_DEVELOPER);
+            return $string; // Return the original string, since it is the best we have.
+        }
+
+        return $normalised;
     }
 
     public function get_correct_response() {
index f9bf057..9160201 100644 (file)
@@ -867,58 +867,180 @@ sup {vertical-align: super;}
 #page-admin-grade-edit-scale-edit.dir-rtl .error input#id_name {margin-right: 170px;}
 .initialbar a {padding-right: 2px;}
 
-/**
- * Chooser Dialogue
- *
- * This CSS belong to the chooser dialogue which should work both with, and
- * without javascript enabled
- */
-/* Hide the dialog and it's title */
-.chooserdialoguebody,
-.choosertitle {
-    display:none;
+/* Moodle Dialogue Settings (moodle-core-dialogue)  */
+.moodle-dialogue-base .moodle-dialogue-lightbox {
+    background-color:#AAA;
 }
 
+.moodle-dialogue-base .hidden,
+.moodle-dialogue-base .moodle-dialogue-hidden {display:none;}
 .moodle-dialogue-base .moodle-dialogue {
-    background: none!important;
-    border: 0 none!important;
+    padding: 0;
+    margin: 0;
+    background: none;
+    border: none;
+    /* Override the z-index set incorrectly by the YUI dialogue */
+    z-index: 600!important;
 }
 
-.chooserdialogue .moodle-dialogue-wrap {
-    height: auto;
+
+.moodle-dialogue-base .moodle-dialogue-wrap {
+    margin-top:-3px;
+    margin-left:-3px;
     background-color: #FFFFFF;
-    border: 1px solid #CCCCCC!important;
+    border: 1px solid #CCCCCC;
     border-radius:10px;
     box-shadow: 5px 5px 20px 0px #666666;
     -webkit-box-shadow: 5px 5px 20px 0px #666666;
     -moz-box-shadow: 5px 5px 20px 0px #666666;
 }
 
-.chooserdialogue .moodle-dialogue-wrap .moodle-dialogue-hd {
-    font-size:12px!important;
-    font-weight: normal!important;
+.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd {
+    margin:0;
+    padding:5px;
+    font-size:12px;
+    font-weight: normal;
     letter-spacing: 1px;
-    color:#333333!important;
-    text-align: center!important;
+    color:#333333;
+    text-align: center;
     text-shadow: 1px 1px 1px #FFFFFF;
-    padding:5px 5px 5px 5px;
     border-radius: 10px 10px 0px 0px;
-    border-bottom: 1px solid #BBBBBB!important;
-    background: #CCCCCC!important;
-    background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC))!important;
-    background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC)!important;
+    border-bottom: 1px solid #BBBBBB;
+    background: #CCCCCC;
+    background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));
+    background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC);
     filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#CCCCCC')!important;
     filter: dropshadow(color=#FFFFFF, offx=1, offy=1);
 }
-/* Activity Chooser "Close" button */
-.dir-rtl .moodle-dialogue-base .closebutton {float: left;}
+
+.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd h1 {
+    margin:0;
+    padding:0;
+    display:inline;
+    font-size: 100%;
+    font-weight: bold;
+}
+.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd .yui3-widget-buttons {
+    padding: 5px;
+}
+.moodle-dialogue-base .closebutton {
+    width:25px;
+    height:15px;
+    float:right;
+    vertical-align:middle;
+    display:inline-block;
+    cursor:pointer;
+    padding:0px;
+    background-image:url([[pix:theme|sprite]]);
+    background-repeat:no-repeat;
+    border-style:none;
+}
+.dir-rtl .moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-hd .yui3-widget-buttons {
+    left: 0px;
+    right: auto;
+}
+
+.moodle-dialogue-base .moodle-dialogue .moodle-dialogue-bd {
+    overflow: auto;
+    padding: 1em;
+    line-height: 2em;
+    color: #555;
+    font-size: 12px;
+}
+
+.moodle-dialogue-base .moodle-dialogue-wrap .moodle-dialogue-content {
+  padding:0px;
+  background:#FFF;
+}
+
+.moodle-dialogue-confirm .confirmation-dialogue {text-align:center;}
+.moodle-dialogue-confirm .confirmation-dialogue input {text-align:center;}
+.moodle-dialogue-exception .moodle-exception-message {text-align:center}
+.moodle-dialogue-exception .moodle-exception-param label {font-weight:bold;}
+.moodle-dialogue-exception .param-stacktrace label {
+    background-color:#EEE;
+    border:1px solid #ccc;
+    border-bottom-width:0;
+}
+
+.moodle-dialogue-exception .param-stacktrace pre {
+    border:1px solid #ccc;
+    background-color:#fff;
+}
+
+.moodle-dialogue-exception .param-stacktrace .stacktrace-file {
+    color:navy
+    font-size:80%
+}
+.moodle-dialogue-exception .param-stacktrace .stacktrace-line {
+    color:#AA0000
+    font-size:80%
+}
+.moodle-dialogue-exception .param-stacktrace .stacktrace-call {
+    color:#333
+    font-size:90%
+    border-bottom:1px solid #eee
+}
+
+.moodle-dialogue-base .moodle-dialogue .moodle-dialogue-content .moodle-dialogue-ft {
+    padding:0px;
+    margin: 0.7em 1em;
+    text-align: right;
+    background-color: #FFF;
+    font-size: 12px;
+}
+
+.moodle-dialogue-confirm .confirmation-message {margin:0.5em 1em;}
+.moodle-dialogue-confirm .confirmation-dialogue input {min-width:80px}
+.moodle-dialogue-exception .moodle-exception-message {margin:1em;}
+.moodle-dialogue-exception .moodle-exception-param {margin-bottom:0.5em;}
+.moodle-dialogue-exception .moodle-exception-param label {width:150px;}
+.moodle-dialogue-exception .param-stacktrace label {
+    display:block;
+    margin:0;
+    padding:4px 1em;
+}
+.moodle-dialogue-exception .param-stacktrace pre {
+    display:block;
+    height:200px;
+    overflow:auto;
+}
+
+.moodle-dialogue-exception .param-stacktrace .stacktrace-file {
+    display:inline-block
+    margin:4px 0
+}
+.moodle-dialogue-exception .param-stacktrace .stacktrace-line {
+    display:inline-block
+    width:50px
+    margin:4px 1em
+}
+.moodle-dialogue-exception .param-stacktrace .stacktrace-call {
+    padding-left:25px
+    margin-bottom:4px
+    padding-bottom:4px
+}
+
+
 /* Question Bank - Question Chooser "Close" button */
 #page-question-edit.dir-rtl a.container-close {right:auto;left:6px;}
 
+/**
+ * Chooser Dialogues (moodle-core-chooserdialogue)
+ *
+ * This CSS belong to the chooser dialogue which should work both with, and
+ * without javascript enabled
+ */
+/* Hide the dialog and it's title */
+.chooserdialoguebody,
+.choosertitle {
+    display:none;
+}
+.moodle-dialogue.chooserdialogue .moodle-dialogue-content .moodle-dialogue-ft {
+    margin: 0;
+}
+
 .chooserdialogue .moodle-dialogue-wrap .moodle-dialogue-bd {
-    font-size: 12px;
-    color: #555555;
-    overflow: auto;
     padding: 0px;
     background: #F2F2F2;
     border-bottom-left-radius: 10px;
index 12b7053..fba454f 100644 (file)
 #combinedfeedbackhdr div.fhtmleditor {padding: 0;}
 #combinedfeedbackhdr div.fcheckbox {margin-bottom: 1em;}
 
+#multitriesheader div.fitem_feditor {margin-top: 1em;}
+#multitriesheader div.fitem_fgroup {margin-bottom: 1em;}
+#multitriesheader div.fitem_fgroup fieldset.felement label {margin-left: 0.3em; margin-right: 0.3em;}
+
 .que {clear: left;text-align: left;margin: 0 auto 1.8em auto;}
 .dir-rtl .que {text-align: right;}
 
index d71f000..20c7d86 100644 (file)
@@ -494,7 +494,7 @@ div.yui3-widget-bd {
     background: none;
 }
 
-div.yui3-widget-bd h1.helpheading {
+div.yui3-widget-bd h2.helpheading {
     font-size: 16px !important;
     font-weight: 800;
     margin-top: 5px;
index b333b1d..575d34c 100644 (file)
@@ -33,7 +33,8 @@ ul {
     color:inherit;
     font-size:inherit;
 }
-h1.helpheading {
+h1.helpheading,
+h2.helpheading {
     font-size: 1.6em;
 }
 /*extra line abve labels and remove padding right for no icon */
index 54d65f2..9439c4e 100644 (file)
@@ -377,8 +377,9 @@ if (!isset($hiddenfields['suspended'])) {
 
 echo "</table></div></div>";
 
-
+echo '<div id="region-content" class="block-region"><div class="region-content">';
 echo $OUTPUT->blocks_for_region('content');
+echo '</div></div>';
 
 // Print messaging link if allowed
 if (isloggedin() && has_capability('moodle/site:sendmessage', $context)