Merge branch 'MDL-46064_master' of git://github.com/markn86/moodle
authorDavid Monllao <davidm@moodle.com>
Tue, 10 Mar 2015 02:23:55 +0000 (10:23 +0800)
committerDavid Monllao <davidm@moodle.com>
Tue, 10 Mar 2015 02:23:55 +0000 (10:23 +0800)
45 files changed:
lang/en/group.php
lib/grouplib.php
lib/moodlelib.php
lib/tests/behat/behat_forms.php
lib/tests/grouplib_test.php
mod/data/backup/moodle2/backup_data_stepslib.php
mod/data/db/install.xml
mod/data/db/upgrade.php
mod/data/edit.php
mod/data/field.php
mod/data/field/checkbox/field.class.php
mod/data/field/checkbox/mod.html
mod/data/field/date/field.class.php
mod/data/field/file/field.class.php
mod/data/field/file/mod.html
mod/data/field/latlong/field.class.php
mod/data/field/latlong/mod.html
mod/data/field/menu/field.class.php
mod/data/field/menu/mod.html
mod/data/field/multimenu/field.class.php
mod/data/field/multimenu/mod.html
mod/data/field/number/mod.html
mod/data/field/picture/field.class.php
mod/data/field/picture/mod.html
mod/data/field/radiobutton/field.class.php
mod/data/field/radiobutton/mod.html
mod/data/field/text/mod.html
mod/data/field/textarea/field.class.php
mod/data/field/textarea/mod.html
mod/data/field/url/field.class.php
mod/data/field/url/mod.html
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/styles.css
mod/data/tests/behat/add_entries.feature
mod/data/tests/behat/required_entries.feature [new file with mode: 0644]
mod/data/tests/behat/view_entries.feature
mod/data/version.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/numerical.php
mod/lesson/pagetypes/shortanswer.php
mod/lesson/pagetypes/truefalse.php
version.php

index 14060bb..5536a7a 100644 (file)
@@ -159,6 +159,8 @@ $string['nousersinrole'] = 'There are no suitable users in the selected role';
 $string['number'] = 'Group/member count';
 $string['numgroups'] = 'Number of groups';
 $string['nummembers'] = 'Members per group';
+$string['mygroups'] = 'My groups';
+$string['othergroups'] = 'Other groups';
 $string['overview'] = 'Overview';
 $string['potentialmembers'] = 'Potential members: {$a}';
 $string['potentialmembs'] = 'Potential members';
index 98ac4be..3f3a233 100644 (file)
@@ -513,8 +513,11 @@ function groups_print_course_menu($course, $urlroot, $return=false) {
     $context = context_course::instance($course->id);
     $aag = has_capability('moodle/site:accessallgroups', $context);
 
+    $usergroups = array();
     if ($groupmode == VISIBLEGROUPS or $aag) {
         $allowedgroups = groups_get_all_groups($course->id, 0, $course->defaultgroupingid);
+        // Get user's own groups and put to the top.
+        $usergroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
     } else {
         $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
     }
@@ -526,11 +529,7 @@ function groups_print_course_menu($course, $urlroot, $return=false) {
         $groupsmenu[0] = get_string('allparticipants');
     }
 
-    if ($allowedgroups) {
-        foreach ($allowedgroups as $group) {
-            $groupsmenu[$group->id] = format_string($group->name);
-        }
-    }
+    $groupsmenu += groups_sort_menu_options($allowedgroups, $usergroups);
 
     if ($groupmode == VISIBLEGROUPS) {
         $grouplabel = get_string('groupsvisible');
@@ -562,6 +561,55 @@ function groups_print_course_menu($course, $urlroot, $return=false) {
     }
 }
 
+/**
+ * Turn an array of groups into an array of menu options.
+ * @param array $groups of group objects.
+ * @return array groupid => formatted group name.
+ */
+function groups_list_to_menu($groups) {
+    $groupsmenu = array();
+    foreach ($groups as $group) {
+        $groupsmenu[$group->id] = format_string($group->name);
+    }
+    return $groupsmenu;
+}
+
+/**
+ * Takes user's allowed groups and own groups and formats for use in group selector menu
+ * If user has allowed groups + own groups will add to an optgroup
+ * Own groups are removed from allowed groups
+ * @param array $allowedgroups All groups user is allowed to see
+ * @param array $usergroups Groups user belongs to
+ * @return array
+ */
+function groups_sort_menu_options($allowedgroups, $usergroups) {
+    $useroptions = array();
+    if ($usergroups) {
+        $useroptions = groups_list_to_menu($usergroups);
+
+        // Remove user groups from other groups list.
+        foreach ($usergroups as $group) {
+            unset($allowedgroups[$group->id]);
+        }
+    }
+
+    $allowedoptions = array();
+    if ($allowedgroups) {
+        $allowedoptions = groups_list_to_menu($allowedgroups);
+    }
+
+    if ($useroptions && $allowedoptions) {
+        return array(
+            1 => array(get_string('mygroups', 'group') => $useroptions),
+            2 => array(get_string('othergroups', 'group') => $allowedoptions)
+        );
+    } else if ($useroptions) {
+        return $useroptions;
+    } else {
+        return $allowedoptions;
+    }
+}
+
 /**
  * Generates html to print menu selector for course level, listing all groups.
  * Note: This api does not do any group mode check use groups_print_course_menu() instead if you want proper checks.
@@ -587,9 +635,7 @@ function groups_allgroups_course_menu($course, $urlroot, $update = false, $activ
         $allowedgroups = groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid);
     }
 
-    foreach ($allowedgroups as $group) {
-        $groupsmenu[$group->id] = format_string($group->name);
-    }
+    $groupsmenu += groups_list_to_menu($allowedgroups);
 
     if ($update) {
         // Init activegroup array if necessary.
@@ -665,8 +711,11 @@ function groups_print_activity_menu($cm, $urlroot, $return=false, $hideallpartic
     $context = context_module::instance($cm->id);
     $aag = has_capability('moodle/site:accessallgroups', $context);
 
+    $usergroups = array();
     if ($groupmode == VISIBLEGROUPS or $aag) {
         $allowedgroups = groups_get_all_groups($cm->course, 0, $cm->groupingid); // any group in grouping
+        // Get user's own groups and put to the top.
+        $usergroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid);
     } else {
         $allowedgroups = groups_get_all_groups($cm->course, $USER->id, $cm->groupingid); // only assigned groups
     }
@@ -678,11 +727,7 @@ function groups_print_activity_menu($cm, $urlroot, $return=false, $hideallpartic
         $groupsmenu[0] = get_string('allparticipants');
     }
 
-    if ($allowedgroups) {
-        foreach ($allowedgroups as $group) {
-            $groupsmenu[$group->id] = format_string($group->name);
-        }
-    }
+    $groupsmenu += groups_sort_menu_options($allowedgroups, $usergroups);
 
     if ($groupmode == VISIBLEGROUPS) {
         $grouplabel = get_string('groupsvisible');
index 2747982..7d8ea2f 100644 (file)
@@ -3143,6 +3143,15 @@ function require_login($courseorid = null, $autologinguest = true, $cm = null, $
         }
     }
 
+    // Set the global $COURSE.
+    // TODO MDL-49434: setting current course/cm should be after the check $cm->uservisible .
+    if ($cm) {
+        $PAGE->set_cm($cm, $course);
+        $PAGE->set_pagelayout('incourse');
+    } else if (!empty($courseorid)) {
+        $PAGE->set_course($course);
+    }
+
     // Check visibility of activity to current user; includes visible flag, conditional availability, etc.
     if ($cm && !$cm->uservisible) {
         if ($preventredirect) {
@@ -3156,14 +3165,6 @@ function require_login($courseorid = null, $autologinguest = true, $cm = null, $
         redirect($url, get_string('activityiscurrentlyhidden'));
     }
 
-    // Set the global $COURSE.
-    if ($cm) {
-        $PAGE->set_cm($cm, $course);
-        $PAGE->set_pagelayout('incourse');
-    } else if (!empty($courseorid)) {
-        $PAGE->set_course($course);
-    }
-
     // Finally access granted, update lastaccess times.
     user_accesstime_log($course->id);
 }
index f7a5a52..fcde598 100644 (file)
@@ -32,6 +32,7 @@ use Behat\Behat\Context\Step\Given as Given,
     Behat\Behat\Context\Step\When as When,
     Behat\Behat\Context\Step\Then as Then,
     Behat\Gherkin\Node\TableNode as TableNode,
+    Behat\Gherkin\Node\PyStringNode as PyStringNode,
     Behat\Mink\Element\NodeElement as NodeElement,
     Behat\Mink\Exception\ExpectationException as ExpectationException,
     Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException;
@@ -159,6 +160,19 @@ class behat_forms extends behat_base {
         $this->set_field_value($field, $value);
     }
 
+    /**
+     * Sets the specified value to the field.
+     *
+     * @Given /^I set the field "(?P<field_string>(?:[^"]|\\")*)" to multiline$/
+     * @throws ElementNotFoundException Thrown by behat_base::find
+     * @param string $field
+     * @param PyStringNode $value
+     * @return void
+     */
+    public function i_set_the_field_to_multiline($field, PyStringNode $value) {
+        $this->set_field_value($field, (string)$value);
+    }
+
     /**
      * Sets the specified value to the field with xpath.
      *
index 5c0d0f3..b200fb9 100644 (file)
@@ -838,4 +838,73 @@ class core_grouplib_testcase extends advanced_testcase {
         $this->assertCount(0, $usergroups1[0]);
         $this->assertCount(0, $usergroups2[0]);
     }
+
+    /**
+     * Create dummy groups array for use in menu tests
+     * @param int $number
+     * @return array
+     */
+    protected function make_group_list($number) {
+        $testgroups = array();
+        for ($a = 0; $a < $number; $a++) {
+            $grp = new stdClass();
+            $grp->id = 100 + $a;
+            $grp->name = 'test group ' . $grp->id;
+            $testgroups[$grp->id] = $grp;
+        }
+        return $testgroups;
+    }
+
+    public function test_groups_sort_menu_options_empty() {
+        $this->assertEquals(array(), groups_sort_menu_options(array(), array()));
+    }
+
+    public function test_groups_sort_menu_options_allowed_goups_only() {
+        $this->assertEquals(array(
+            100 => 'test group 100',
+            101 => 'test group 101',
+        ), groups_sort_menu_options($this->make_group_list(2), array()));
+    }
+
+    public function test_groups_sort_menu_options_user_goups_only() {
+        $this->assertEquals(array(
+            100 => 'test group 100',
+            101 => 'test group 101',
+        ), groups_sort_menu_options(array(), $this->make_group_list(2)));
+    }
+
+    public function test_groups_sort_menu_options_user_both() {
+        $this->assertEquals(array(
+            1 => array(get_string('mygroups', 'group') => array(
+                100 => 'test group 100',
+                101 => 'test group 101',
+            )),
+            2 => array(get_string('othergroups', 'group') => array(
+                102 => 'test group 102',
+                103 => 'test group 103',
+            )),
+        ), groups_sort_menu_options($this->make_group_list(4), $this->make_group_list(2)));
+    }
+
+    public function test_groups_sort_menu_options_user_both_many_groups() {
+        $this->assertEquals(array(
+            1 => array(get_string('mygroups', 'group') => array(
+                100 => 'test group 100',
+                101 => 'test group 101',
+            )),
+            2 => array (get_string('othergroups', 'group') => array(
+                102 => 'test group 102',
+                103 => 'test group 103',
+                104 => 'test group 104',
+                105 => 'test group 105',
+                106 => 'test group 106',
+                107 => 'test group 107',
+                108 => 'test group 108',
+                109 => 'test group 109',
+                110 => 'test group 110',
+                111 => 'test group 111',
+                112 => 'test group 112',
+            )),
+        ), groups_sort_menu_options($this->make_group_list(13), $this->make_group_list(2)));
+    }
 }
index 5fe9ee6..385e66b 100644 (file)
@@ -50,7 +50,7 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
         $fields = new backup_nested_element('fields');
 
         $field = new backup_nested_element('field', array('id'), array(
-            'type', 'name', 'description', 'param1', 'param2',
+            'type', 'name', 'description', 'required', 'param1', 'param2',
             'param3', 'param4', 'param5', 'param6',
             'param7', 'param8', 'param9', 'param10'));
 
index 37b46f1..c4a5c2c 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="mod/data/db" VERSION="20120122" COMMENT="XMLDB file for Moodle mod/data"
+<XMLDB PATH="mod/data/db" VERSION="20150309" COMMENT="XMLDB file for Moodle mod/data"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
 >
@@ -54,6 +54,7 @@
         <FIELD NAME="type" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="name" TYPE="char" LENGTH="255" NOTNULL="true" SEQUENCE="false"/>
         <FIELD NAME="description" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
+        <FIELD NAME="required" TYPE="int" LENGTH="1" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Required fields must have a value when inserted by a user"/>
         <FIELD NAME="param1" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="param2" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="param3" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
         <FIELD NAME="fieldid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
         <FIELD NAME="recordid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
-        <FIELD NAME="content" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
-        <FIELD NAME="content1" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
-        <FIELD NAME="content2" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
-        <FIELD NAME="content3" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
-        <FIELD NAME="content4" TYPE="text" LENGTH="big" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="content" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="content1" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="content2" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="content3" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
+        <FIELD NAME="content4" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
   </TABLES>
-</XMLDB>
\ No newline at end of file
+</XMLDB>
index 61c57d5..c5251ea 100644 (file)
@@ -137,7 +137,18 @@ function xmldb_data_upgrade($oldversion) {
     // Moodle v2.8.0 release upgrade line.
     // Put any upgrade step following this.
 
-    return true;
-}
+    if ($oldversion < 2015030900) {
+        // Define field required to be added to data_fields.
+        $table = new xmldb_table('data_fields');
+        $field = new xmldb_field('required', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'description');
+
+        // Conditionally launch add field required.
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
 
+        upgrade_mod_savepoint(true, 2015030900, 'data');
+    }
 
+    return true;
+}
index 6dd59f7..7350cca 100644 (file)
@@ -34,8 +34,14 @@ $rid   = optional_param('rid', 0, PARAM_INT);    //record id
 $cancel   = optional_param('cancel', '', PARAM_RAW);    // cancel an add
 $mode ='addtemplate';    //define the mode for this page, only 1 mode available
 
+
+
 $url = new moodle_url('/mod/data/edit.php');
 if ($rid !== 0) {
+    $record = $DB->get_record('data_records', array(
+            'id' => $rid,
+            'dataid' => $d,
+        ), '*', MUST_EXIST);
     $url->param('rid', $rid);
 }
 if ($cancel !== '') {
@@ -152,105 +158,121 @@ if ($rid) {
 $PAGE->set_title($data->name);
 $PAGE->set_heading($course->fullname);
 
-/// Process incoming data for adding/updating records
+// Process incoming data for adding/updating records.
+
+// Keep track of any notifications.
+$generalnotifications = array();
+$fieldnotifications = array();
 
+// Process the submitted form.
 if ($datarecord = data_submitted() and confirm_sesskey()) {
+    if ($rid) {
+        // Updating an existing record.
 
-    $ignorenames = array('MAX_FILE_SIZE','sesskey','d','rid','saveandview','cancel');  // strings to be ignored in input data
+        // Retrieve the format for the fields.
+        $fields = $DB->get_records('data_fields', array('dataid' => $datarecord->d));
 
-    if ($rid) {                                          /// Update some records
+        // Validate the form to ensure that enough data was submitted.
+        $processeddata = data_process_submission($data, $fields, $datarecord);
 
-        /// All student edits are marked unapproved by default
-        $record = $DB->get_record('data_records', array('id'=>$rid));
+        // Add the new notification data.
+        $generalnotifications = array_merge($generalnotifications, $processeddata->generalnotifications);
+        $fieldnotifications = array_merge($fieldnotifications, $processeddata->fieldnotifications);
 
-        /// reset approved flag after student edit
-        if (!has_capability('mod/data:approve', $context)) {
-            $record->approved = 0;
-        }
+        if ($processeddata->validated) {
+            // Enough data to update the record.
 
-        $record->timemodified = time();
-        $DB->update_record('data_records', $record);
+            // Obtain the record to be updated.
 
-        /// Update all content
-        $field = NULL;
-        foreach ($datarecord as $name => $value) {
-            if (!in_array($name, $ignorenames)) {
-                $namearr = explode('_',$name);  // Second one is the field id
-                if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
-                    $field = data_get_field_from_id($namearr[1], $data);
-                }
-                if ($field) {
-                    $field->update_content($rid, $value, $name);
-                }
+            // Reset the approved flag after edit if the user does not have permission to approve their own entries.
+            if (!has_capability('mod/data:approve', $context)) {
+                $record->approved = 0;
             }
-        }
 
-        // Trigger an event for updating this record.
-        $event = \mod_data\event\record_updated::create(array(
-            'objectid' => $rid,
-            'context' => $context,
-            'courseid' => $course->id,
-            'other' => array(
-                'dataid' => $data->id
-            )
-        ));
-        $event->add_record_snapshot('data', $data);
-        $event->trigger();
-
-        redirect($CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&rid='.$rid);
-
-    } else { /// Add some new records
-        ///Empty form checking - you can't submit an empty form!
-
-        $emptyform = true;      // assume the worst
-
-        foreach ($datarecord as $name => $value) {
-            if (!in_array($name, $ignorenames)) {
-                $namearr = explode('_', $name);  // Second one is the field id
-                if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
-                    $field = data_get_field_from_id($namearr[1], $data);
-                }
-                if ($field->notemptyfield($value, $name)) {
-                    $emptyform = false;
-                    break;             // if anything has content, this form is not empty, so stop now!
-                }
+            // Update the parent record.
+            $record->timemodified = time();
+            $DB->update_record('data_records', $record);
+
+            // Update all content.
+            foreach ($processeddata->fields as $fieldname => $field) {
+                $field->update_content($rid, $datarecord->$fieldname, $fieldname);
             }
-        }
 
-        if ($emptyform){    //nothing gets written to database
-            echo $OUTPUT->notification(get_string('emptyaddform','data'));
+            // Trigger an event for updating this record.
+            $event = \mod_data\event\record_updated::create(array(
+                'objectid' => $rid,
+                'context' => $context,
+                'courseid' => $course->id,
+                'other' => array(
+                    'dataid' => $data->id
+                )
+            ));
+            $event->add_record_snapshot('data', $data);
+            $event->trigger();
+
+            $viewurl = new moodle_url('/mod/data/view.php', array(
+                'd' => $data->id,
+                'rid' => $rid,
+            ));
+            redirect($viewurl);
         }
 
-        if (!$emptyform && $recordid = data_add_record($data, $currentgroup)) {    //add instance to data_record
+    } else {
+        // No recordid was specified - creating a new entry.
 
-            /// Insert a whole lot of empty records to make sure we have them
-            $fields = $DB->get_records('data_fields', array('dataid'=>$data->id));
+        // Retrieve the format for the fields.
+        $fields = $DB->get_records('data_fields', array('dataid' => $datarecord->d));
+
+        // Validate the form to ensure that enough data was submitted.
+        $processeddata = data_process_submission($data, $fields, $datarecord);
+
+        // Add the new notification data.
+        $generalnotifications = array_merge($generalnotifications, $processeddata->generalnotifications);
+        $fieldnotifications = array_merge($fieldnotifications, $processeddata->fieldnotifications);
+
+        // Add instance to data_record.
+        if ($processeddata->validated && $recordid = data_add_record($data, $currentgroup)) {
+
+            // Insert a whole lot of empty records to make sure we have them.
+            $records = array();
             foreach ($fields as $field) {
                 $content = new stdClass();
                 $content->recordid = $recordid;
                 $content->fieldid = $field->id;
-                $DB->insert_record('data_content',$content);
+                $records[] = $content;
             }
 
-            /// For each field in the add form, add it to the data_content.
-            foreach ($datarecord as $name => $value){
-                if (!in_array($name, $ignorenames)) {
-                    $namearr = explode('_', $name);  // Second one is the field id
-                    if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
-                        $field = data_get_field_from_id($namearr[1], $data);
-                    }
-                    if ($field) {
-                        $field->update_content($recordid, $value, $name);
-                    }
-                }
+            // Bulk insert the records now. Some records may have no data but all must exist.
+            $DB->insert_records('data_content', $records);
+
+            // Add all provided content.
+            foreach ($processeddata->fields as $fieldname => $field) {
+                $field->update_content($recordid, $datarecord->$fieldname, $fieldname);
             }
 
+            // Trigger an event for updating this record.
+            $event = \mod_data\event\record_created::create(array(
+                'objectid' => $rid,
+                'context' => $context,
+                'courseid' => $course->id,
+                'other' => array(
+                    'dataid' => $data->id
+                )
+            ));
+            $event->add_record_snapshot('data', $data);
+            $event->trigger();
+
             if (!empty($datarecord->saveandview)) {
-                redirect($CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&rid='.$recordid);
+                $viewurl = new moodle_url('/mod/data/view.php', array(
+                    'd' => $data->id,
+                    'rid' => $recordid,
+                ));
+                redirect($viewurl);
             }
         }
     }
-}  // End of form processing
+}
+// End of form processing.
 
 
 /// Print the page header
@@ -300,9 +322,18 @@ if ($data->addtemplate){
 
         // To skip unnecessary calls to display_add_field().
         if (strpos($data->addtemplate, "[[".$field->field->name."]]") !== false) {
+            // Replace the field tag.
             $patterns[] = "[[".$field->field->name."]]";
-            $replacements[] = $field->display_add_field($rid);
+            $errors = '';
+            if (!empty($fieldnotifications[$field->field->name])) {
+                foreach ($fieldnotifications[$field->field->name] as $notification) {
+                    $errors .= $OUTPUT->notification($notification);
+                }
+            }
+            $replacements[] = $errors . $field->display_add_field($rid, $datarecord);
         }
+
+        // Replace the field id tag.
         $patterns[] = "[[".$field->field->name."#id]]";
         $replacements[] = 'field_'.$field->field->id;
     }
@@ -313,6 +344,9 @@ if ($data->addtemplate){
     $newtext = '';
 }
 
+foreach ($generalnotifications as $notification) {
+    echo $OUTPUT->notification($notification);
+}
 echo $newtext;
 
 echo '<div class="mdl-align"><input type="submit" name="saveandview" value="'.get_string('saveandview','data').'" />';
index e567fff..77e3a29 100644 (file)
@@ -146,6 +146,7 @@ switch ($mode) {
 
                 $field->field->name = $fieldinput->name;
                 $field->field->description = $fieldinput->description;
+                $field->field->required = !empty($fieldinput->required) ? 1 : 0;
 
                 for ($i=1; $i<=10; $i++) {
                     if (isset($fieldinput->{'param'.$i})) {
@@ -264,7 +265,13 @@ if (($mode == 'new') && (!empty($newtype)) && confirm_sesskey()) {          ///
     } else {    //else print quiz style list of fields
 
         $table = new html_table();
-        $table->head = array(get_string('fieldname','data'), get_string('type','data'), get_string('fielddescription', 'data'), get_string('action','data'));
+        $table->head = array(
+            get_string('fieldname', 'data'),
+            get_string('type', 'data'),
+            get_string('required', 'data'),
+            get_string('fielddescription', 'data'),
+            get_string('action', 'data'),
+        );
         $table->align = array('left','left','left', 'center');
         $table->wrap = array(false,false,false,false);
 
@@ -273,21 +280,28 @@ if (($mode == 'new') && (!empty($newtype)) && confirm_sesskey()) {          ///
 
                 $field = data_get_field($ff, $data);
 
-                $table->data[] = array(
-
-                '<a href="field.php?mode=display&amp;d='.$data->id.
-                '&amp;fid='.$field->field->id.'&amp;sesskey='.sesskey().'">'.$field->field->name.'</a>',
+                $baseurl = new moodle_url('/mod/data/field.php', array(
+                    'd'         => $data->id,
+                    'fid'       => $field->field->id,
+                    'sesskey'   => sesskey(),
+                ));
 
-                $field->image().'&nbsp;'.get_string($field->type, 'data'),
+                $displayurl = new moodle_url($baseurl, array(
+                    'mode'      => 'display',
+                ));
 
-                shorten_text($field->field->description, 30),
-
-                '<a href="field.php?d='.$data->id.'&amp;mode=display&amp;fid='.$field->field->id.'&amp;sesskey='.sesskey().'">'.
-                '<img src="'.$OUTPUT->pix_url('t/edit') . '" class="iconsmall" alt="'.get_string('edit').'" title="'.get_string('edit').'" /></a>'.
-                '&nbsp;'.
-                '<a href="field.php?d='.$data->id.'&amp;mode=delete&amp;fid='.$field->field->id.'&amp;sesskey='.sesskey().'">'.
-                '<img src="'.$OUTPUT->pix_url('t/delete') . '" class="iconsmall" alt="'.get_string('delete').'" title="'.get_string('delete').'" /></a>'
+                $deleteurl = new moodle_url($baseurl, array(
+                    'mode'      => 'delete',
+                ));
 
+                $table->data[] = array(
+                    html_writer::link($displayurl, $field->field->name),
+                    $field->image() . '&nbsp;' . get_string($field->type, 'data'),
+                    $field->field->required ? get_string('yes') : get_string('no'),
+                    shorten_text($field->field->description, 30),
+                    html_writer::link($displayurl, $OUTPUT->pix_icon('t/edit', get_string('edit'))) .
+                        '&nbsp;' .
+                        html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete'))),
                 );
             }
         }
index 7571d07..8b7c0a6 100644 (file)
@@ -26,20 +26,33 @@ class data_field_checkbox extends data_field_base {
 
     var $type = 'checkbox';
 
-    function display_add_field($recordid=0) {
-        global $CFG, $DB;
+    function display_add_field($recordid = 0, $formdata = null) {
+        global $CFG, $DB, $OUTPUT;
 
         $content = array();
 
-        if ($recordid) {
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id;
+            $content = $formdata->$fieldname;
+        } else if ($recordid) {
             $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
             $content = explode('##', $content);
         } else {
             $content = array();
         }
 
-        $str = '<div title="'.s($this->field->description).'">';
-        $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+        $str = '<div title="' . s($this->field->description) . '">';
+        $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name;
+        if ($this->field->required) {
+            $str .= '$nbsp;' . get_string('requiredelement', 'form');
+            $str .= '</span></legend>';
+            $str .= '<div>';
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $str .= '</div>';
+        } else {
+            $str .= '</span></legend>';
+        }
 
         $i = 0;
         foreach (explode("\n", $this->field->param1) as $checkbox) {
@@ -211,5 +224,22 @@ class data_field_checkbox extends data_field_base {
         return implode('##', $vals);
     }
 
-}
+    /**
+     * Check whether any boxes in the checkbox where checked.
+     *
+     * @param mixed $value The submitted values
+     * @param mixed $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        $found = false;
+        foreach ($value as $checkboxitem) {
+            if (!empty($checkboxitem)) {
+                $found = true;
+                break;
+            }
+        }
+        return $found;
+    }
 
+}
index a881292..c6dfcaa 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description); ?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required ? "checked=\"checked\"" : ""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
         <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
index 2fa245d..fc5f4a9 100644 (file)
@@ -34,10 +34,18 @@ class data_field_date extends data_field_base {
     var $month = 0;
     var $year  = 0;
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $DB, $OUTPUT;
 
-        if ($recordid) {
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_day';
+            $day   = $formdata->$fieldname;
+            $fieldname = 'field_' . $this->field->id . '_month';
+            $month   = $formdata->$fieldname;
+            $fieldname = 'field_' . $this->field->id . '_year';
+            $year   = $formdata->$fieldname;
+            $content = make_timestamp($year, $month, $day, 12, 0, 0, 0, false);
+        } else if ($recordid) {
             $content = (int)$DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
         } else {
             $content = time();
@@ -128,5 +136,3 @@ class data_field_date extends data_field_base {
 
 
 }
-
-
index 5fd2d21..b1cee24 100644 (file)
@@ -25,7 +25,7 @@
 class data_field_file extends data_field_base {
     var $type = 'file';
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $CFG, $DB, $OUTPUT, $PAGE, $USER;
 
         $file        = false;
@@ -36,7 +36,10 @@ class data_field_file extends data_field_base {
         $itemid = null;
 
         // editing an existing database entry
-        if ($recordid){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_file';
+            $itemid = $formdata->$fieldname;
+        } else if ($recordid) {
             if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
 
                 file_prepare_draft_area($itemid, $this->context->id, 'mod_data', 'content', $content->id);
@@ -62,10 +65,18 @@ class data_field_file extends data_field_base {
             $itemid = file_get_unused_draft_itemid();
         }
 
-        $html = '';
         // database entry label
-        $html .= '<div title="'.s($this->field->description).'">';
-        $html .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+        $html = '<div title="' . s($this->field->description) . '">';
+        $html .= '<fieldset><legend><span class="accesshide">'.$this->field->name;
+
+        if ($this->field->required) {
+            $html .= '&nbsp;' . get_string('requiredelement', 'form') . '</span></legend>';
+            $image = html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $html .= html_writer::div($image);
+        } else {
+            $html .= '</span></legend>';
+        }
 
         // itemid element
         $html .= '<input type="hidden" name="field_'.$this->field->id.'_file" value="'.$itemid.'" />';
@@ -83,7 +94,6 @@ class data_field_file extends data_field_base {
 
         $output = $PAGE->get_renderer('core', 'files');
         $html .= $output->render($fm);
-
         $html .= '</fieldset>';
         $html .= '</div>';
 
@@ -204,6 +214,24 @@ class data_field_file extends data_field_base {
         return true;
     }
 
-}
-
+    /**
+     * Custom notempty function
+     *
+     * @param string $value
+     * @param string $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        global $USER;
+
+        $names = explode('_', $name);
+        if ($names[2] == 'file') {
+            $usercontext = context_user::instance($USER->id);
+            $fs = get_file_storage();
+            $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $value);
+            return count($files) >= 2;
+        }
+        return false;
+    }
 
+}
index 8f8945c..2f67d9a 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description);?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required ? "checked=\"checked\"" : ""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param3">
             <?php echo get_string('maxsize', 'data'); ?></label></td>
index e6108ee..d89df71 100644 (file)
@@ -43,12 +43,17 @@ class data_field_latlong extends data_field_base {
     );
     // Other map sources listed at http://kvaleberg.com/extensions/mapsources/index.php?params=51_30.4167_N_0_7.65_W_region:earth
 
-    function display_add_field($recordid=0) {
-        global $CFG, $DB;
+    function display_add_field($recordid = 0, $formdata = null) {
+        global $CFG, $DB, $OUTPUT;
 
         $lat = '';
         $long = '';
-        if ($recordid) {
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_0';
+            $lat = $formdata->$fieldname;
+            $fieldname = 'field_' . $this->field->id . '_1';
+            $long = $formdata->$fieldname;
+        } else if ($recordid) {
             if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
                 $lat  = $content->content;
                 $long = $content->content1;
@@ -57,8 +62,21 @@ class data_field_latlong extends data_field_base {
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
         $str .= '<table><tr><td align="right">';
-        $str .= '<label for="field_'.$this->field->id.'_0">' . get_string('latitude', 'data') . '</label></td><td><input type="text" name="field_'.$this->field->id.'_0" id="field_'.$this->field->id.'_0" value="'.s($lat).'" size="10" />°N</td></tr>';
-        $str .= '<tr><td align="right"><label for="field_'.$this->field->id.'_1">' . get_string('longitude', 'data') . '</label></td><td><input type="text" name="field_'.$this->field->id.'_1" id="field_'.$this->field->id.'_1" value="'.s($long).'" size="10" />°E</td></tr>';
+        $str .= '<label for="field_'.$this->field->id.'_0">' . get_string('latitude', 'data');
+        if ($this->field->required) {
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+        }
+        $str .= '</label></td><td><input type="text" name="field_'.$this->field->id.'_0" id="field_'.$this->field->id.'_0" value="';
+        $str .= s($lat).'" size="10" />°N</td></tr>';
+        $str .= '<tr><td align="right"><label for="field_'.$this->field->id.'_1">' . get_string('longitude', 'data');
+        if ($this->field->required) {
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+        }
+        $str .= '</label></td><td><input type="text" name="field_'.$this->field->id.'_1" id="field_'.$this->field->id.'_1" value="';
+        $str .= s($long).'" size="10" />°E</td>';
+        $str .= '</tr>';
         $str .= '</table>';
         $str .= '</fieldset>';
         $str .= '</div>';
@@ -223,6 +241,15 @@ class data_field_latlong extends data_field_base {
         return sprintf('%01.4f', $record->content) . ' ' . sprintf('%01.4f', $record->content1);
     }
 
-}
-
+    /**
+     * Check if a field from an add form is empty
+     *
+     * @param mixed $value
+     * @param mixed $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        return isset($value) && !($value == '');
+    }
 
+}
index fb34fb4..1b0466d 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p ($this->field->description);?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param1"><?php echo get_string('latlonglinkservicesdisplayed', 'data'); ?></label></td>
         <td class="c1">
index 4fb611b..c53e3cb 100644 (file)
@@ -26,17 +26,19 @@ class data_field_menu extends data_field_base {
 
     var $type = 'menu';
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $DB, $OUTPUT;
 
-        if ($recordid){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id;
+            $content = $formdata->$fieldname;
+        } else if ($recordid) {
             $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
             $content = trim($content);
         } else {
             $content = '';
         }
-
-        $str = '<div title="'.s($this->field->description).'">';
+        $str = '<div title="' . s($this->field->description) . '">';
 
         $options = array();
         $rawoptions = explode("\n",$this->field->param1);
@@ -47,7 +49,14 @@ class data_field_menu extends data_field_base {
             }
         }
 
-        $str .= html_writer::label(get_string('menuchoose', 'data'), 'field_'.$this->field->id, false, array('class' => 'accesshide'));
+        $str .= '<label for="' . 'field_' . $this->field->id . '">';
+        $str .= html_writer::span($this->field->name, 'accesshide');
+        if ($this->field->required) {
+            $image = html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $str .= html_writer::div($image);
+        }
+        $str .= '</label>';
         $str .= html_writer::select($options, 'field_'.$this->field->id, $content, array(''=>get_string('menuchoose', 'data')), array('id'=>'field_'.$this->field->id));
 
         $str .= '</div>';
@@ -108,5 +117,3 @@ class data_field_menu extends data_field_base {
     }
 
 }
-
-
index f92fb13..e7c84e3 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description);?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
         <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
index 1f3de9f..75b6bc0 100644 (file)
@@ -26,10 +26,17 @@ class data_field_multimenu extends data_field_base {
 
     var $type = 'multimenu';
 
-    function display_add_field($recordid=0) {
-        global $DB;
+    function display_add_field($recordid = 0, $formdata = null) {
+        global $DB, $OUTPUT;
 
-        if ($recordid){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id;
+            if (isset($formdata->$fieldname)) {
+                $content = $formdata->$fieldname;
+            } else {
+                $content = array();
+            }
+        } else if ($recordid) {
             $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
             $content = explode('##', $content);
         } else {
@@ -38,10 +45,19 @@ class data_field_multimenu extends data_field_base {
 
         $str = '<div title="'.s($this->field->description).'">';
         $str .= '<input name="field_' . $this->field->id . '[xxx]" type="hidden" value="xxx"/>'; // hidden field - needed for empty selection
-        $str .= '<label class="accesshide" for="field_' . $this->field->id . '">' . $this->field->name. '</label>';
+
+        $str .= '<label for="field_' . $this->field->id . '">';
+        $str .= html_writer::span($this->field->name, 'accesshide');
+        if ($this->field->required) {
+            $str .= '<div>';
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $str .= '</div>';
+        }
+        $str .= '</label>';
         $str .= '<select name="field_' . $this->field->id . '[]" id="field_' . $this->field->id . '" multiple="multiple">';
 
-        foreach (explode("\n",$this->field->param1) as $option) {
+        foreach (explode("\n", $this->field->param1) as $option) {
             $option = trim($option);
             $str .= '<option value="' . s($option) . '"';
 
@@ -238,5 +254,16 @@ class data_field_multimenu extends data_field_base {
         }
         return false;
     }
-}
 
+    /**
+     * Check if a field from an add form is empty
+     *
+     * @param mixed $value
+     * @param mixed $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        unset($value['xxx']);
+        return !empty($value);
+    }
+}
index a881292..58db398 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description); ?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
         <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
index 831560f..7b1791b 100644 (file)
@@ -7,4 +7,8 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description);?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
 </table>
index a459791..d4ade19 100644 (file)
@@ -27,7 +27,7 @@ class data_field_picture extends data_field_base {
     var $previewwidth  = 50;
     var $previewheight = 50;
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $CFG, $DB, $OUTPUT, $USER, $PAGE;
 
         $file        = false;
@@ -37,7 +37,14 @@ class data_field_picture extends data_field_base {
         $itemid = null;
         $fs = get_file_storage();
 
-        if ($recordid) {
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_file';
+            $itemid = $formdata->$fieldname;
+            $fieldname = 'field_' . $this->field->id . '_alttext';
+            if (isset($formdata->$fieldname)) {
+                $alttext = $formdata->$fieldname;
+            }
+        } else if ($recordid) {
             if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
                 file_prepare_draft_area($itemid, $this->context->id, 'mod_data', 'content', $content->id);
                 if (!empty($content->content)) {
@@ -64,9 +71,17 @@ class data_field_picture extends data_field_base {
         } else {
             $itemid = file_get_unused_draft_itemid();
         }
-
-        $str = '<div title="'.s($this->field->description).'">';
-        $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+        $str = '<div title="' . s($this->field->description) . '">';
+        $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name;
+
+        if ($this->field->required) {
+            $str .= '&nbsp;' . get_string('requiredelement', 'form') . '</span></legend>';
+            $image = html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                      array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $str .= html_writer::div($image);
+        } else {
+            $str .= '</span></legend>';
+        }
         $str .= '<noscript>';
         if ($file) {
             $src = file_encode_url($CFG->wwwroot.'/pluginfile.php/', $this->context->id.'/mod_data/content/'.$content->id.'/'.$file->get_filename());
@@ -290,6 +305,24 @@ class data_field_picture extends data_field_base {
     function file_ok($path) {
         return true;
     }
-}
 
+    /**
+     * Custom notempty function
+     *
+     * @param string $value
+     * @param string $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        global $USER;
 
+        $names = explode('_', $name);
+        if ($names[2] == 'file') {
+            $usercontext = context_user::instance($USER->id);
+            $fs = get_file_storage();
+            $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $value);
+            return count($files) >= 2;
+        }
+        return false;
+    }
+}
index 99fd424..c008976 100644 (file)
             <input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description);?>" />
         </td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param1">
             <?php echo get_string('fieldwidthsingleview', 'data');?></label></td>
index f3115c1..3008fb0 100644 (file)
@@ -26,20 +26,38 @@ class data_field_radiobutton extends data_field_base {
 
     var $type = 'radiobutton';
 
-    function display_add_field($recordid=0) {
-        global $CFG, $DB;
+    function display_add_field($recordid = 0, $formdata = null) {
+        global $CFG, $DB, $OUTPUT;
 
-        if ($recordid){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id;
+            if (isset($formdata->$fieldname)) {
+                $content = $formdata->$fieldname;
+            } else {
+                $content = '';
+            }
+        } else if ($recordid) {
             $content = trim($DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid)));
         } else {
             $content = '';
         }
 
-        $str = '<div title="'.s($this->field->description).'">';
-        $str .= '<fieldset><legend><span class="accesshide">'.$this->field->name.'</span></legend>';
+        $str = '<div title="' . s($this->field->description) . '">';
+        $str .= '<fieldset><legend><span class="accesshide">' . $this->field->name;
+
+        if ($this->field->required) {
+            $str .= '&nbsp;' . get_string('requiredelement', 'form') . '</span></legend>';
+            $image = html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                      array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+            $str .= html_writer::div($image);
+        } else {
+            $str .= '</span></legend>';
+        }
 
         $i = 0;
-        foreach (explode("\n",$this->field->param1) as $radio) {
+        $requiredstr = '';
+        $options = explode("\n", $this->field->param1);
+        foreach ($options as $radio) {
             $radio = trim($radio);
             if ($radio === '') {
                 continue; // skip empty lines
index a881292..58db398 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description); ?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0" valign="top"><label for="param1"><?php echo get_string('fieldoptions', 'data'); ?></label></td>
         <td class="c1"><textarea class="optionstextarea" name="param1" id="param1" cols="80" rows="10"><?php if($this->field->param1) {p($this->field->param1);} ?></textarea></td>
index 940ff1c..597e763 100644 (file)
@@ -7,6 +7,10 @@
         <td class="c0"><label for="description"><?php echo get_string('fielddescription', 'data'); ?></label></td>
         <td class="c1"><input class="fielddescription" type="text" name="description" id="description" value="<?php p($this->field->description); ?>" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param1"><?php echo get_string('fieldallowautolink', 'data'); ?></label></td>
         <td class="c1"><input type="checkbox" name="param1" id="param1" <?php if($this->field->param1) {echo 'checked="checked"';} ?> value="1" /></td>
index 51ad6fc..dda933e 100644 (file)
@@ -49,13 +49,19 @@ class data_field_textarea extends data_field_base {
         return $options;
     }
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $CFG, $DB, $OUTPUT, $PAGE;
 
         $text   = '';
         $format = 0;
-
-        $str = '<div title="'.$this->field->description.'">';
+        $str = '<div title="' . s($this->field->description) . '">';
+        $str .= '<label for="field_' . $this->field->id . '">';
+        $str .= html_writer::span($this->field->name, "accesshide");
+        if ($this->field->required) {
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+        }
+        $str .= '</label>';
 
         editors_head_setup();
         $options = $this->get_options();
@@ -63,7 +69,25 @@ class data_field_textarea extends data_field_base {
         $itemid = $this->field->id;
         $field = 'field_'.$itemid;
 
-        if ($recordid && $content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_content1';
+            if (isset($formdata->$fieldname)) {
+                $format = $formdata->$fieldname;
+            } else {
+                $format = file_get_unused_draft_itemid();
+            }
+            $fieldname = 'field_' . $this->field->id . '_itemid';
+            if (isset($formdata->$fieldname)) {
+                $draftitemid = $formdata->$fieldname;
+            } else {
+                $draftitemid = file_get_unused_draft_itemid();
+            }
+            $fieldname = 'field_' . $this->field->id;
+            if (isset($formdata->$fieldname)) {
+                $text = $formdata->$fieldname;
+            }
+        } else if ($recordid &&
+                   $content = $DB->get_record('data_content', array('fieldid' => $this->field->id, 'recordid' => $recordid))) {
             $format = $content->content1;
             $text = clean_text($content->content, $format);
             $text = file_prepare_draft_area($draftitemid, $this->context->id, 'mod_data', 'content', $content->id, $options, $text);
@@ -129,8 +153,8 @@ class data_field_textarea extends data_field_base {
             $str .= '<option value="'.s($key).'" '.$selected.'>'.$desc.'</option>';
         }
         $str .= '</select>';
-        $str .= '</div>';
 
+        $str .= '</div>';
         $str .= '</div>';
         return $str;
     }
@@ -230,5 +254,20 @@ class data_field_textarea extends data_field_base {
     function file_ok($relativepath) {
         return true;
     }
-}
 
+    /**
+     * Only look at the first item (second is format)
+     *
+     * @param string $value
+     * @param string $name
+     * @return bool
+     */
+    function notemptyfield($value, $name) {
+        $names = explode('_', $name);
+        // Clean first.
+        if (count($names) == 2) {
+            return !empty($value);
+        }
+        return false;
+    }
+}
index e75365a..e3dbc78 100644 (file)
             value="<?php p($this->field->description); ?>" />
         </td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param2">
             <?php echo get_string('fieldwidth', 'data'); ?></label></td>
index eb0c4c5..b89ecce 100644 (file)
@@ -25,7 +25,7 @@
 class data_field_url extends data_field_base {
     var $type = 'url';
 
-    function display_add_field($recordid=0) {
+    function display_add_field($recordid = 0, $formdata = null) {
         global $CFG, $DB, $OUTPUT, $PAGE;
 
         require_once($CFG->dirroot. '/repository/lib.php'); // necessary for the constants used in args
@@ -43,24 +43,39 @@ class data_field_url extends data_field_base {
         $straddlink = get_string('choosealink', 'repository');
         $url = '';
         $text = '';
-        if ($recordid) {
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id . '_0';
+            $url = $formdata->$fieldname;
+            $fieldname = 'field_' . $this->field->id . '_1';
+            if (isset($formdata->$fieldname)) {
+                $text = $formdata->$fieldname;
+            }
+        } else if ($recordid) {
             if ($content = $DB->get_record('data_content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))) {
                 $url  = $content->content;
                 $text = $content->content1;
             }
         }
-        $str = '<div title="'.s($this->field->description).'">';
+        $str = '<div title="' . s($this->field->description) . '">';
+
+        $label = '<label for="' . $fieldid . '"><span class="accesshide">' . $this->field->name . '</span>';
+        if ($this->field->required) {
+            $label .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                      array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+        }
+        $label .= '</label>';
+
         if (!empty($this->field->param1) and empty($this->field->param2)) {
             $str .= '<table><tr><td align="right">';
             $str .= get_string('url','data').':</td><td>';
-            $str .= '<label class="accesshide" for="' . $fieldid . '">'. $this->field->name .'</label>';
+            $str .= $label;
             $str .= '<input type="text" name="field_'.$this->field->id.'_0" id="'.$fieldid.'" value="'.$url.'" size="60" />';
             $str .= '<button id="filepicker-button-'.$options->client_id.'" style="display:none">'.$straddlink.'</button></td></tr>';
             $str .= '<tr><td align="right">'.get_string('text','data').':</td><td><input type="text" name="field_'.$this->field->id.'_1" id="field_'.$this->field->id.'_1" value="'.s($text).'" size="60" /></td></tr>';
             $str .= '</table>';
         } else {
             // Just the URL field
-            $str .= '<label class="accesshide" for="' . $fieldid . '">'. $this->field->name .'</label>';
+            $str .= $label;
             $str .= '<input type="text" name="field_'.$this->field->id.'_0" id="'.$fieldid.'" value="'.s($url).'" size="60" />';
             if (count($options->repositories) > 0) {
                 $str .= '<button id="filepicker-button-'.$options->client_id.'" class="visibleifjs">'.$straddlink.'</button>';
@@ -72,7 +87,6 @@ class data_field_url extends data_field_base {
 
         $module = array('name'=>'data_urlpicker', 'fullpath'=>'/mod/data/data.js', 'requires'=>array('core_filepicker'));
         $PAGE->requires->js_init_call('M.data_urlpicker.init', array($options), true, $module);
-
         $str .= '</div>';
         return $str;
     }
@@ -178,5 +192,3 @@ class data_field_url extends data_field_base {
     }
 
 }
-
-
index e33b467..afb5dc3 100644 (file)
         <td class="c0"><label for="param1"><?php echo get_string('autolinkurl', 'data') ?></label></td>
         <td class="c1"><input type="checkbox" name="param1" id="param1" <?php if($this->field->param1) {echo 'checked="checked"';} ?> value="1" /></td>
     </tr>
+    <tr>
+        <td class="c0"><label for="required"><?php echo get_string('requiredfield', 'data'); ?></label></td>
+        <td class="c1"><input class="requiredfield" type="checkbox" name="required" id="required" <?php p($this->field->required?"checked=\"checked\"":""); ?>/></td>
+    </tr>
     <tr>
         <td class="c0"><label for="param3"><?php echo get_string('openlinkinnewwindow', 'datafield_url') ?></label></td>
         <td class="c1"><input type="checkbox" name="param3" id="param3" <?php if($this->field->param3) {echo 'checked="checked"';} ?> value="1" /></td>
index 5b6cc5a..f9ec9dc 100644 (file)
@@ -135,6 +135,7 @@ $string['entry'] = 'Entry';
 $string['entrysaved'] = 'Your entry has been saved';
 $string['errormustbeteacher'] = 'You need to be a teacher to use this page!';
 $string['errorpresetexists'] = 'There is already a preset with the selected name';
+$string['errormustsupplyvalue'] = 'You must supply a value here.';
 $string['example'] = 'Database module example';
 $string['excel'] = 'Excel';
 $string['export'] = 'Export';
@@ -302,12 +303,14 @@ $string['recordsnotsaved'] = 'No entry was saved. Please check the format of the
 $string['recordssaved'] = 'entries saved';
 $string['requireapproval'] = 'Approval required';
 $string['requireapproval_help'] = 'If enabled, entries require approving by a teacher before they are viewable by everyone.';
+$string['required'] = 'Required';
 $string['requiredentries'] = 'Entries required for completion';
 $string['requiredentries_help'] = 'The number of entries a student is required to submit before the activity can be considered complete.';
 $string['requiredentriestoview'] = 'Entries required before viewing';
 $string['requiredentriestoview_help'] = 'The number of entries a student is required to submit before they can view entries from other students.
 
 Note: If entries are required before viewing, the database auto-linking filter should be disabled. This is because the database auto-linking filter can\'t determine whether a user has submitted the required number of entries.';
+$string['requiredfield'] = 'Required field';
 $string['resetsettings'] = 'Reset filters';
 $string['resettemplate'] = 'Reset template';
 $string['resizingimages'] = 'Resizing image thumbnails...';
index 7adbedd..5c3cc5e 100644 (file)
@@ -137,6 +137,7 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
         $this->field->param3 = '';
         $this->field->name = '';
         $this->field->description = '';
+        $this->field->required = false;
 
         return true;
     }
@@ -152,6 +153,7 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
 
         $this->field->name        = trim($data->name);
         $this->field->description = trim($data->description);
+        $this->field->required    = !empty($data->required) ? 1 : 0;
 
         if (isset($data->param1)) {
             $this->field->param1 = trim($data->param1);
@@ -268,10 +270,13 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
      * @param int $recordid
      * @return string
      */
-    function display_add_field($recordid=0){
-        global $DB;
+    function display_add_field($recordid=0, $formdata=null) {
+        global $DB, $OUTPUT;
 
-        if ($recordid){
+        if ($formdata) {
+            $fieldname = 'field_' . $this->field->id;
+            $content = $formdata->$fieldname;
+        } else if ($recordid) {
             $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid));
         } else {
             $content = '';
@@ -282,9 +287,14 @@ class data_field_base {     // Base class for Database Field Types (see field/*/
             $content='';
         }
 
-        $str = '<div title="'.s($this->field->description).'">';
-        $str .= '<label class="accesshide" for="field_'.$this->field->id.'">'.$this->field->description.'</label>';
-        $str .= '<input class="basefieldinput" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id.'" value="'.s($content).'" />';
+        $str = '<div title="' . s($this->field->description) . '">';
+        $str .= '<label for="field_'.$this->field->id.'"><span class="accesshide">'.$this->field->name.'</span>';
+        if ($this->field->required) {
+            $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'),
+                                     array('class' => 'req', 'title' => get_string('requiredelement', 'form')));
+        }
+        $str .= '</label><input class="basefieldinput" type="text" name="field_'.$this->field->id.'" id="field_'.$this->field->id;
+        $str .= '" value="'.s($content).'" />';
         $str .= '</div>';
 
         return $str;
@@ -548,7 +558,7 @@ function data_generate_default_template(&$data, $template, $recordid=0, $form=fa
         foreach ($fields as $field) {
             if ($form) {   // Print forms instead of data
                 $fieldobj = data_get_field($field, $data);
-                $token = $fieldobj->display_add_field($recordid);
+                $token = $fieldobj->display_add_field($recordid, null);
             } else {           // Just print the tag
                 $token = '[['.$field->name.']]';
             }
@@ -3751,3 +3761,95 @@ function data_delete_record($recordid, $data, $courseid, $cmid) {
     }
     return false;
 }
+
+/**
+ * Check for required fields, and build a list of fields to be updated in a
+ * submission.
+ *
+ * @param $mod stdClass The current recordid - provided as an optimisation.
+ * @param $fields array The field data
+ * @param $datarecord stdClass The submitted data.
+ * @return stdClass containing:
+ * * string[] generalnotifications Notifications for the form as a whole.
+ * * string[] fieldnotifications Notifications for a specific field.
+ * * bool validated Whether the field was validated successfully.
+ * * data_field_base[] fields The field objects to be update.
+ */
+function data_process_submission(stdClass $mod, $fields, stdClass $datarecord) {
+    $result = new stdClass();
+
+    // Empty form checking - you can't submit an empty form.
+    $emptyform = true;
+    $requiredfieldsfilled = true;
+
+    // Store the notifications.
+    $result->generalnotifications = array();
+    $result->fieldnotifications = array();
+
+    // Store the instantiated classes as an optimisation when processing the result.
+    // This prevents the fields being re-initialised when updating.
+    $result->fields = array();
+
+    $submitteddata = array();
+    foreach ($datarecord as $fieldname => $fieldvalue) {
+        if (strpos($fieldname, '_')) {
+            $namearray = explode('_', $fieldname, 3);
+            $fieldid = $namearray[1];
+            if (!isset($submitteddata[$fieldid])) {
+                $submitteddata[$fieldid] = array();
+            }
+            if (count($namearray) === 2) {
+                $subfieldid = 0;
+            } else {
+                $subfieldid = $namearray[2];
+            }
+
+            $fielddata = new stdClass();
+            $fielddata->fieldname = $fieldname;
+            $fielddata->value = $fieldvalue;
+            $submitteddata[$fieldid][$subfieldid] = $fielddata;
+        }
+    }
+
+    // Check all form fields which have the required are filled.
+    foreach ($fields as $fieldrecord) {
+        // Check whether the field has any data.
+        $fieldhascontent = false;
+
+        $field = data_get_field($fieldrecord, $mod);
+        if (isset($submitteddata[$fieldrecord->id])) {
+            foreach ($submitteddata[$fieldrecord->id] as $fieldname => $value) {
+                if ($field->notemptyfield($value->value, $value->fieldname)) {
+                    // The field has content and the form is not empty.
+                    $fieldhascontent = true;
+                    $emptyform = false;
+                }
+            }
+        }
+
+        // If the field is required, add a notification to that effect.
+        if ($field->field->required && !$fieldhascontent) {
+            if (!isset($result->fieldnotifications[$field->field->name])) {
+                $result->fieldnotifications[$field->field->name] = array();
+            }
+            $result->fieldnotifications[$field->field->name][] = get_string('errormustsupplyvalue', 'data');
+            $requiredfieldsfilled = false;
+        }
+
+        if ($fieldhascontent) {
+            // The field has content so it should be updatable.
+            foreach ($submitteddata[$fieldrecord->id] as $value) {
+                $result->fields[$value->fieldname] = $field;
+            }
+        }
+    }
+
+    if ($emptyform) {
+        // The form is empty.
+        $result->generalnotifications[] = get_string('emptyaddform', 'data');
+    }
+
+    $result->validated = $requiredfieldsfilled && !$emptyform;
+
+    return $result;
+}
index 955b3cd..242de98 100644 (file)
@@ -68,3 +68,7 @@
 .dir-rtl .mod-data-default-template .template-field {text-align:left;}
 .dir-rtl .mod-data-default-template .template-token {text-align:right;}
 .dir-rtl .mod-data-default-template searchcontrols {text-align:left;}
+
+#page-mod-data-edit .req {
+    cursor: help;
+}
index d8182f3..3a2e3a3 100644 (file)
@@ -31,19 +31,19 @@ Feature: Users can add entries to database activities
     When I log in as "student1"
     And I follow "Course 1"
     And I add an entry to "Test database name" database with:
-      | Test field description | Student original entry |
+      | Test field name | Student original entry |
     And I press "Save and view"
     Then I should see "Student original entry"
     And I follow "Edit"
     And I set the following fields to these values:
-      | Test field description | Student edited entry |
+      | Test field name | Student edited entry |
     And I press "Save and view"
     And I should see "Student edited entry"
     And I add an entry to "Test database name" database with:
-      | Test field description | Student second entry |
+      | Test field name | Student second entry |
     And I press "Save and add another"
     And I add an entry to "Test database name" database with:
-      | Test field description | Student third entry |
+      | Test field name | Student third entry |
     And I press "Save and view"
     And I follow "View list"
     And I should see "Student edited entry"
diff --git a/mod/data/tests/behat/required_entries.feature b/mod/data/tests/behat/required_entries.feature
new file mode 100644 (file)
index 0000000..40d19c1
--- /dev/null
@@ -0,0 +1,206 @@
+@mod @mod_data
+Feature: Users can be required to specify certain fields when adding entries to database activities
+  In order to constrain user input
+  As a teacher
+  I need to specify certain fields as required when I add entries to databases
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | student1 | Student | 1 | student1@asd.com |
+      | teacher1 | Teacher | 1 | teacher1@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 the following "activities" exist:
+      | activity | name               | intro | course | idnumber |
+      | data     | Test database name | n     | C1     | data1    |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I add a "Text input" field to "Test database name" database and I fill the form with:
+      | Field name | Base Text input |
+      | Required | yes |
+      | Field description | Base Text input |
+    And I add a "Checkbox" field to "Test database name" database and I fill the form with:
+      | Field name | Required Checkbox |
+      | Field description | Required Checkbox |
+      | Required | yes |
+      | Options | Required Checkbox Option 1 |
+    And I follow "Fields"
+    And I set the field "newtype" to "Checkbox"
+    And I click on "Go" "button" in the ".fieldadd" "css_element"
+    And I set the following fields to these values:
+      | Field name | Required Two-Option Checkbox |
+      | Field description | Required Two-Option Checkbox |
+      | Required | yes |
+    And I set the field "Options" to multiline
+    """
+    RTOC Option 1
+    RTOC Option 2
+    """
+    And I press "Add"
+    And I add a "Latlong" field to "Test database name" database and I fill the form with:
+      | Field name | Required Latlong |
+      | Field description | Required Latlong |
+      | Required | yes |
+    And I add a "Menu" field to "Test database name" database and I fill the form with:
+      | Field name | Required Menu |
+      | Field description | Required Menu |
+      | Required | yes |
+      | Options | Option 1 |
+    And I add a "Number" field to "Test database name" database and I fill the form with:
+      | Field name | Required Number |
+      | Field description | Required Number |
+      | Required | yes |
+    And I add a "Radio button" field to "Test database name" database and I fill the form with:
+      | Field name | Required Radio |
+      | Field description | Required Radio |
+      | Required | yes |
+      | Options | Required Radio Option 1 |
+    And I add a "Text input" field to "Test database name" database and I fill the form with:
+      | Field name | Required Text input |
+      | Field description | Required Text input |
+      | Required | yes |
+    And I add a "Text area" field to "Test database name" database and I fill the form with:
+      | Field name | Required Text area |
+      | Field description | Required Text area |
+      | Required | yes |
+    And I add a "URL" field to "Test database name" database and I fill the form with:
+      | Field name | Required URL |
+      | Field description | Required URL |
+      | Required | yes |
+    And I add a "Multimenu" field to "Test database name" database and I fill the form with:
+      | Field name | Required Multimenu |
+      | Field description | Required Multimenu |
+      | Required | yes |
+      | Options | Option 1 |
+    And I follow "Fields"
+    And I set the field "newtype" to "Multimenu"
+    And I click on "Go" "button" in the ".fieldadd" "css_element"
+    And I set the following fields to these values:
+      | Field name | Required Two-Option Multimenu |
+      | Field description | Required Two-Option Multimenu |
+      | Required | yes |
+    And I set the field "Options" to multiline
+    """
+    Option 1
+    Option 2
+    """
+    And I press "Add"
+    And I add a "Checkbox" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Checkbox |
+      | Field description | Not required Checkbox |
+      | Options | Not required Checkbox Option 1 |
+    And I add a "Latlong" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Latlong |
+      | Field description | Not required Latlong |
+    And I add a "Menu" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Menu |
+      | Field description | Not required Menu |
+      | Options | Option 1 |
+    And I add a "Number" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Number |
+      | Field description | Not required Number |
+    And I add a "Radio button" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Radio |
+      | Field description | Not required Radio |
+      | Options | Not required Radio Option 1 |
+    And I add a "Text input" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Text input |
+      | Field description | Not required Text input |
+    And I add a "Text area" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Text area |
+      | Field description | Not required Text area |
+    And I add a "URL" field to "Test database name" database and I fill the form with:
+      | Field name | Not required URL |
+      | Field description | Not required URL |
+    And I add a "Multimenu" field to "Test database name" database and I fill the form with:
+      | Field name | Not required Multimenu |
+      | Field description | Not required Multimenu |
+      | Options | Option 1 |
+    And I follow "Templates"
+    And I log out
+
+  Scenario: Students receive errors for empty required fields but not for optional fields
+    When I log in as "student1"
+    And I follow "Course 1"
+    And I add an entry to "Test database name" database with:
+       | Base Text input | Some input to allow us to submit the otherwise empty form |
+    And I press "Save and view"
+    Then ".alert.alert-error" "css_element" should exist in the "Required Checkbox" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Two-Option Checkbox" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Latlong" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Menu" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Number" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Radio" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Text input" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Text area" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required URL" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Multimenu" "table_row"
+    And ".alert.alert-error" "css_element" should exist in the "Required Two-Option Multimenu" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Checkbox" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Latlong" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Menu" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Number" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Radio" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Text input" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Text area" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required URL" "table_row"
+    And ".alert.alert-error" "css_element" should not exist in the "Not required Multimenu" "table_row"
+    And I follow "View list"
+    And I should see "No entries in database"
+
+  Scenario: Students recieve no error for filled in required fields
+    When I log in as "student1"
+    And I follow "Course 1"
+    And I add an entry to "Test database name" database with:
+       | Base Text input               | Some input to allow us to submit the otherwise empty form |
+       | Required Checkbox Option 1    | 1                                                         |
+       | RTOC Option 1                 | 1                                                         |
+       | Latitude                      | 0                                                         |
+       | Longitude                     | 0                                                         |
+       | Required Menu                 | 1                                                         |
+       | Required Number               | 1                                                         |
+       | Required Radio Option 1       | 1                                                         |
+       | Required Text input           | New entry text                                            |
+       | Required Text area            | More text                                                 |
+       | Required URL                  | http://example.com/                                       |
+       | Required Multimenu            | 1                                                         |
+       | Required Two-Option Multimenu | 1                                                         |
+    And I press "Save and view"
+    And I follow "View list"
+    Then I should not see "No entries in database"
+    And I should see "New entry text"
+
+  Scenario: Fields refill with data after having an error
+    When I log in as "student1"
+    And I follow "Course 1"
+    And I add an entry to "Test database name" database with:
+       | RTOC Option 1                 | 1                   |
+       | Latitude                      | 0                   |
+       | Longitude                     | 0                   |
+       | Required Menu                 | 1                   |
+       | Required Number               | 1                   |
+       | Required Radio Option 1       | 1                   |
+       | Required Text input           | New entry text      |
+       | Required Text area            | More text           |
+       | Required URL                  | http://example.com/ |
+       | Required Multimenu            | 1                   |
+       | Required Two-Option Multimenu | 1                   |
+    And I press "Save and view"
+    Then the following fields match these values:
+       | Base Text input               |                     |
+       | Latitude                      | 0                   |
+       | Longitude                     | 0                   |
+       | Required Menu                 | Option 1            |
+       | Required Number               | 1                   |
+       | Required Radio Option 1       | 1                   |
+       | Required Text input           | New entry text      |
+       | Required Text area            | More text           |
+       | Required URL                  | http://example.com/ |
+       | Required Multimenu            | Option 1            |
+       | Required Two-Option Multimenu | Option 1            |
index 833ce42..29d7a70 100644 (file)
@@ -27,13 +27,13 @@ Feature: Users can view and search database entries
     # To generate the default templates.
     And I follow "Templates"
     And I add an entry to "Test database name" database with:
-      | Test field description | Teacher entry 1 |
+      | Test field name | Teacher entry 1 |
     And I press "Save and add another"
     And I add an entry to "Test database name" database with:
-      | Test field description | Teacher entry 2 |
+      | Test field name | Teacher entry 2 |
     And I press "Save and add another"
     And I add an entry to "Test database name" database with:
-      | Test field description | Teacher entry 3 |
+      | Test field name | Teacher entry 3 |
     And I press "Save and view"
     And I log out
     When I log in as "student1"
index 369c277..bb79562 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2014111000;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2015030900;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2014110400;       // Requires this Moodle version
 $plugin->component = 'mod_data';       // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 0;
index 546a7db..9592180 100644 (file)
@@ -318,6 +318,9 @@ class lesson_display_answer_form_essay extends moodleform {
             }
         }
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
index 29775df..59bfd1e 100644 (file)
@@ -533,6 +533,9 @@ class lesson_display_answer_form_matching extends moodleform {
         $lessonid = $this->_customdata['lessonid'];
         $contents = $this->_customdata['contents'];
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
index 41ca410..501b17b 100644 (file)
@@ -488,6 +488,9 @@ class lesson_display_answer_form_multichoice_singleanswer extends moodleform {
             $attempt->answerid = null;
         }
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
@@ -541,6 +544,9 @@ class lesson_display_answer_form_multichoice_multianswer extends moodleform {
         $lessonid = $this->_customdata['lessonid'];
         $contents = $this->_customdata['contents'];
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
index 9e5414a..f8f98e0 100644 (file)
@@ -276,6 +276,9 @@ class lesson_display_answer_form_numerical extends moodleform {
         $mform = $this->_form;
         $contents = $this->_customdata['contents'];
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
index 798b180..1bcc96f 100644 (file)
@@ -369,6 +369,9 @@ class lesson_display_answer_form_shortanswer extends moodleform {
             $attrs['size'] = round(strlen($placeholder) * 1.1);
         }
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
index 8c8056a..ae8fbaf 100644 (file)
@@ -382,6 +382,9 @@ class lesson_display_answer_form_truefalse extends moodleform {
             $attempt->answerid = null;
         }
 
+        // Disable shortforms.
+        $mform->setDisableShortforms();
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
index fee9e93..7b4d1f6 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$version  = 2015030500.00;              // YYYYMMDD      = weekly release date of this DEV branch.
+$version  = 2015030900.00;              // YYYYMMDD      = weekly release date of this DEV branch.
                                         //         RR    = release increments - 00 in DEV branches.
                                         //           .XX = incremental changes.
 
-$release  = '2.9dev (Build: 20150305)'; // Human-friendly version name
+$release  = '2.9dev (Build: 20150309)'; // Human-friendly version name
 
 $branch   = '29';                       // This version's branch.
 $maturity = MATURITY_ALPHA;             // This version's maturity level.