From 9776f3dcdb3b21b622ea8a650fe2ef6b545f7fd1 Mon Sep 17 00:00:00 2001 From: John Okely Date: Mon, 23 Feb 2015 14:47:05 +0800 Subject: [PATCH 1/3] MDL-5583 behat: Add multiline version of 'And I set the field to' --- lib/tests/behat/behat_forms.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/tests/behat/behat_forms.php b/lib/tests/behat/behat_forms.php index f7a5a529e65..fcde5986263 100644 --- a/lib/tests/behat/behat_forms.php +++ b/lib/tests/behat/behat_forms.php @@ -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(?:[^"]|\\")*)" 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. * From b89cca197e4d6447d12fdb7d3fa928edc8a0c837 Mon Sep 17 00:00:00 2001 From: Damyon Wiese Date: Wed, 11 Jul 2012 13:01:30 +0800 Subject: [PATCH 2/3] MDL-5583 mod_data: Add required fields This is implemented for most fields but not all. The reason is that there are some fields for which this does not make sense because no entry is a valid entry. The supported fields are: checkbox file latlong menu number picture radio text textarea url The unsupported fields are: date multimenu --- .../backup/moodle2/backup_data_stepslib.php | 2 +- mod/data/db/install.xml | 13 +- mod/data/db/upgrade.php | 14 +- mod/data/edit.php | 178 +++++++++++------- mod/data/field.php | 44 +++-- mod/data/field/checkbox/field.class.php | 33 +++- mod/data/field/checkbox/mod.html | 4 + mod/data/field/date/field.class.php | 21 ++- mod/data/field/file/field.class.php | 38 +++- mod/data/field/file/mod.html | 4 + mod/data/field/latlong/field.class.php | 27 ++- mod/data/field/latlong/mod.html | 4 + mod/data/field/menu/field.class.php | 20 +- mod/data/field/menu/mod.html | 5 + mod/data/field/multimenu/field.class.php | 8 +- mod/data/field/number/mod.html | 4 + mod/data/field/picture/field.class.php | 40 +++- mod/data/field/picture/mod.html | 5 + mod/data/field/radiobutton/field.class.php | 28 ++- mod/data/field/radiobutton/mod.html | 5 + mod/data/field/text/mod.html | 5 + mod/data/field/textarea/field.class.php | 41 +++- mod/data/field/textarea/mod.html | 5 + mod/data/field/url/field.class.php | 23 ++- mod/data/field/url/mod.html | 4 + mod/data/lang/en/data.php | 4 + mod/data/lib.php | 113 ++++++++++- mod/data/styles.css | 11 ++ mod/data/tests/behat/required_entries.feature | 113 +++++++++++ mod/data/version.php | 2 +- 30 files changed, 665 insertions(+), 153 deletions(-) create mode 100644 mod/data/tests/behat/required_entries.feature diff --git a/mod/data/backup/moodle2/backup_data_stepslib.php b/mod/data/backup/moodle2/backup_data_stepslib.php index 5fe9ee6f87a..385e66bb070 100644 --- a/mod/data/backup/moodle2/backup_data_stepslib.php +++ b/mod/data/backup/moodle2/backup_data_stepslib.php @@ -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')); diff --git a/mod/data/db/install.xml b/mod/data/db/install.xml index 37b46f1d798..aeddfb62e3f 100644 --- a/mod/data/db/install.xml +++ b/mod/data/db/install.xml @@ -1,5 +1,5 @@ - @@ -54,6 +54,7 @@ + @@ -93,11 +94,11 @@ - - - - - + + + + + diff --git a/mod/data/db/upgrade.php b/mod/data/db/upgrade.php index 61c57d57640..d818ddbd616 100644 --- a/mod/data/db/upgrade.php +++ b/mod/data/db/upgrade.php @@ -133,11 +133,21 @@ function xmldb_data_upgrade($oldversion) { // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. + if ($oldversion < 2014051201) { + // 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, 2014051201, 'data'); + } // Moodle v2.8.0 release upgrade line. // Put any upgrade step following this. return true; } - - diff --git a/mod/data/edit.php b/mod/data/edit.php index 6dd59f75e69..7dc11db0a4d 100644 --- a/mod/data/edit.php +++ b/mod/data/edit.php @@ -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(); + // Update the parent record. + $record->timemodified = time(); + $DB->update_record('data_records', $record); - 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 all content. + foreach ($processeddata->fields as $fieldname => $field) { + $field->update_content($rid, $datarecord->$fieldname, $fieldname); } + + // 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){ //nothing gets written to database - echo $OUTPUT->notification(get_string('emptyaddform','data')); - } + } else { + // No recordid was specified - creating a new entry. - if (!$emptyform && $recordid = data_add_record($data, $currentgroup)) { //add instance to data_record + // Retrieve the format for the fields. + $fields = $DB->get_records('data_fields', array('dataid' => $datarecord->d)); - /// Insert a whole lot of empty records to make sure we have them - $fields = $DB->get_records('data_fields', array('dataid'=>$data->id)); + // 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); } + + // 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 '
'; diff --git a/mod/data/field.php b/mod/data/field.php index e567fff4285..0258590034a 100644 --- a/mod/data/field.php +++ b/mod/data/field.php @@ -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); + $baseurl = new moodle_url('/mod/data/field.php', array( + 'd' => $data->id, + 'fid' => $field->field->id, + 'sesskey' => sesskey(), + )); + + $displayurl = new moodle_url($baseurl, array( + 'mode' => 'display', + )); + + $deleteurl = new moodle_url($baseurl, array( + 'mode' => 'delete', + )); + $table->data[] = array( - - ''.$field->field->name.'', - - $field->image().' '.get_string($field->type, 'data'), - - shorten_text($field->field->description, 30), - - ''. - ''.get_string('edit').''. - ' '. - ''. - ''.get_string('delete').'' - + html_writer::link($displayurl, $field->field->name), + $field->image() . ' ' . 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'))) . + ' ' . + html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete'))), ); } } diff --git a/mod/data/field/checkbox/field.class.php b/mod/data/field/checkbox/field.class.php index 7571d077a5a..500dd2181c8 100644 --- a/mod/data/field/checkbox/field.class.php +++ b/mod/data/field/checkbox/field.class.php @@ -26,19 +26,27 @@ class data_field_checkbox extends data_field_base { var $type = 'checkbox'; - function display_add_field($recordid=0) { + function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB; $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 = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $str .= '
'.$this->field->name.''; $i = 0; @@ -211,5 +219,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; + } +} diff --git a/mod/data/field/checkbox/mod.html b/mod/data/field/checkbox/mod.html index a8812926b95..c6dfcaa503d 100644 --- a/mod/data/field/checkbox/mod.html +++ b/mod/data/field/checkbox/mod.html @@ -7,6 +7,10 @@ + + + field->required ? "checked=\"checked\"" : ""); ?>/> + diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php index 2fa245d2984..9361e31e773 100644 --- a/mod/data/field/date/field.class.php +++ b/mod/data/field/date/field.class.php @@ -34,16 +34,29 @@ 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(); } - $str = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $dayselector = html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content); $monthselector = html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content); $yearselector = html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content); @@ -128,5 +141,3 @@ class data_field_date extends data_field_base { } - - diff --git a/mod/data/field/file/field.class.php b/mod/data/field/file/field.class.php index 5fd2d215d2d..567c852064e 100644 --- a/mod/data/field/file/field.class.php +++ b/mod/data/field/file/field.class.php @@ -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); @@ -64,7 +67,11 @@ class data_field_file extends data_field_base { $html = ''; // database entry label - $html .= '
'; + if ($this->field->required) { + $html .= '
'; + } else { + $html .= '
'; + } $html .= '
'.$this->field->name.''; // itemid element @@ -84,6 +91,9 @@ class data_field_file extends data_field_base { $output = $PAGE->get_renderer('core', 'files'); $html .= $output->render($fm); + if ($this->field->required) { + $html .= '' . get_string('requiredfieldshort', 'data') . ''; + } $html .= '
'; $html .= '
'; @@ -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; + } + } - - diff --git a/mod/data/field/file/mod.html b/mod/data/field/file/mod.html index 8f8945c5bca..2f67d9adc61 100644 --- a/mod/data/field/file/mod.html +++ b/mod/data/field/file/mod.html @@ -7,6 +7,10 @@ + + + field->required ? "checked=\"checked\"" : ""); ?>/> + diff --git a/mod/data/field/latlong/field.class.php b/mod/data/field/latlong/field.class.php index e6108eec2bb..47990c1e187 100644 --- a/mod/data/field/latlong/field.class.php +++ b/mod/data/field/latlong/field.class.php @@ -43,24 +43,41 @@ 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) { + function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB; $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; } } - $str = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $str .= '
'.$this->field->name.''; $str .= ''; - $str .= ''; + $str .= ''; + if ($this->field->required) { + $str .= ''; + } + $str .= ''; $str .= '
'; $str .= '°N
°E
°E' . get_string('requiredfieldshort', 'data') . '
'; $str .= '
'; + if ($this->field->required) { + $str .= get_string('requiredfieldhint', 'data', s($this->field->description)); + } $str .= '
'; return $str; } @@ -224,5 +241,3 @@ class data_field_latlong extends data_field_base { } } - - diff --git a/mod/data/field/latlong/mod.html b/mod/data/field/latlong/mod.html index fb34fb4ed75..1b0466d9a8a 100644 --- a/mod/data/field/latlong/mod.html +++ b/mod/data/field/latlong/mod.html @@ -7,6 +7,10 @@ + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/menu/field.class.php b/mod/data/field/menu/field.class.php index 4fb611bae42..d78b4caa73b 100644 --- a/mod/data/field/menu/field.class.php +++ b/mod/data/field/menu/field.class.php @@ -26,17 +26,24 @@ 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 = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $options = array(); $rawoptions = explode("\n",$this->field->param1); @@ -49,6 +56,9 @@ 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 .= html_writer::select($options, 'field_'.$this->field->id, $content, array(''=>get_string('menuchoose', 'data')), array('id'=>'field_'.$this->field->id)); + if ($this->field->required) { + $str .= '' . get_string('requiredfieldshort', 'data') . ''; + } $str .= '
'; @@ -108,5 +118,3 @@ class data_field_menu extends data_field_base { } } - - diff --git a/mod/data/field/menu/mod.html b/mod/data/field/menu/mod.html index f92fb136b23..62a4b018c29 100644 --- a/mod/data/field/menu/mod.html +++ b/mod/data/field/menu/mod.html @@ -7,6 +7,11 @@ + + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/multimenu/field.class.php b/mod/data/field/multimenu/field.class.php index 1f3de9ff00a..18f680d6769 100644 --- a/mod/data/field/multimenu/field.class.php +++ b/mod/data/field/multimenu/field.class.php @@ -26,10 +26,13 @@ class data_field_multimenu extends data_field_base { var $type = 'multimenu'; - function display_add_field($recordid=0) { + function display_add_field($recordid = 0, $formdata = null) { global $DB; - 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 { @@ -239,4 +242,3 @@ class data_field_multimenu extends data_field_base { return false; } } - diff --git a/mod/data/field/number/mod.html b/mod/data/field/number/mod.html index 831560f1b57..7b1791b0a68 100644 --- a/mod/data/field/number/mod.html +++ b/mod/data/field/number/mod.html @@ -7,4 +7,8 @@ + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/picture/field.class.php b/mod/data/field/picture/field.class.php index a459791f790..94a6e29b868 100644 --- a/mod/data/field/picture/field.class.php +++ b/mod/data/field/picture/field.class.php @@ -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,10 @@ 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; + } 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,8 +67,12 @@ class data_field_picture extends data_field_base { } else { $itemid = file_get_unused_draft_itemid(); } - - $str = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $str .= '
'.$this->field->name.''; $str .= '
'; $str .= '
'; @@ -290,6 +300,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; + } } - - diff --git a/mod/data/field/picture/mod.html b/mod/data/field/picture/mod.html index 99fd424b734..47cd7ab8cee 100644 --- a/mod/data/field/picture/mod.html +++ b/mod/data/field/picture/mod.html @@ -12,6 +12,11 @@ + + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/radiobutton/field.class.php b/mod/data/field/radiobutton/field.class.php index f3115c12db8..9ae2e2893fc 100644 --- a/mod/data/field/radiobutton/field.class.php +++ b/mod/data/field/radiobutton/field.class.php @@ -26,20 +26,32 @@ class data_field_radiobutton extends data_field_base { var $type = 'radiobutton'; - function display_add_field($recordid=0) { + function display_add_field($recordid = 0, $formdata = null) { global $CFG, $DB; - if ($recordid){ + if ($formdata) { + $fieldname = 'field_' . $this->field->id; + $content = $formdata->$fieldname; + } else if ($recordid){ $content = trim($DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid))); } else { $content = ''; } - - $str = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $str .= '
'.$this->field->name.''; $i = 0; - foreach (explode("\n",$this->field->param1) as $radio) { + $requiredstr = ''; + if ($this->field->required) { + $requiredstr = '' . get_string('requiredfieldshort', 'data') . ''; + } + $options = explode("\n",$this->field->param1); + foreach ($options as $radio) { $radio = trim($radio); if ($radio === '') { continue; // skip empty lines @@ -54,7 +66,11 @@ class data_field_radiobutton extends data_field_base { $str .= '/>'; } - $str .= '
'; + $str .= ''; + if ($i == count($options) - 1) { + $str .= $requiredstr; + } + $str .= '
'; $i++; } $str .= '
'; diff --git a/mod/data/field/radiobutton/mod.html b/mod/data/field/radiobutton/mod.html index a8812926b95..ebe8538f6e2 100644 --- a/mod/data/field/radiobutton/mod.html +++ b/mod/data/field/radiobutton/mod.html @@ -7,6 +7,11 @@ + + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/text/mod.html b/mod/data/field/text/mod.html index 940ff1cf3d6..fa104817053 100644 --- a/mod/data/field/text/mod.html +++ b/mod/data/field/text/mod.html @@ -7,6 +7,11 @@ + + + + field->required?"checked=\"checked\"":""); ?>/> + field->param1) {echo 'checked="checked"';} ?> value="1" /> diff --git a/mod/data/field/textarea/field.class.php b/mod/data/field/textarea/field.class.php index 51ad6fc8dd5..442e8b5bb32 100644 --- a/mod/data/field/textarea/field.class.php +++ b/mod/data/field/textarea/field.class.php @@ -49,13 +49,17 @@ 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 = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } editors_head_setup(); $options = $this->get_options(); @@ -63,7 +67,14 @@ 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'; + $format = $formdata->$fieldname; + $fieldname = 'field_' . $this->field->id . '_itemid'; + $draftitemid = $formdata->$fieldname; + $fieldname = 'field_' . $this->field->id; + $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 +140,11 @@ class data_field_textarea extends data_field_base { $str .= ''; } $str .= ''; - $str .= '
'; + if ($this->field->required) { + $str .= '' . get_string('requiredfieldshort', 'data') . ''; + } + $str .= '
'; $str .= '
'; return $str; } @@ -230,5 +244,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; + } +} diff --git a/mod/data/field/textarea/mod.html b/mod/data/field/textarea/mod.html index e75365abf9f..cf1143d2c36 100644 --- a/mod/data/field/textarea/mod.html +++ b/mod/data/field/textarea/mod.html @@ -10,6 +10,11 @@ value="field->description); ?>" /> + + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/url/field.class.php b/mod/data/field/url/field.class.php index eb0c4c57d66..7557c279bec 100644 --- a/mod/data/field/url/field.class.php +++ b/mod/data/field/url/field.class.php @@ -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,13 +43,25 @@ 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 = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } if (!empty($this->field->param1) and empty($this->field->param2)) { $str .= ' + + + + diff --git a/mod/data/lang/en/data.php b/mod/data/lang/en/data.php index 5b6cc5adbe3..1e040587389 100644 --- a/mod/data/lang/en/data.php +++ b/mod/data/lang/en/data.php @@ -302,12 +302,16 @@ $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['requiredfieldhint'] = '{$a} (required field)'; +$string['requiredfieldshort'] = ' *'; $string['resetsettings'] = 'Reset filters'; $string['resettemplate'] = 'Reset template'; $string['resizingimages'] = 'Resizing image thumbnails...'; diff --git a/mod/data/lib.php b/mod/data/lib.php index 7adbedd7f3f..f3ae01f87ea 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -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){ + function display_add_field($recordid=0, $formdata=null){ global $DB; - 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,17 @@ class data_field_base { // Base class for Database Field Types (see field/*/ $content=''; } - $str = '
'; + $str = ''; + if ($this->field->required) { + $str .= '
'; + } else { + $str .= '
'; + } $str .= ''; $str .= ''; + if ($this->field->required) { + $str .= '' . get_string('requiredfieldshort', 'data') . ''; + } $str .= '
'; return $str; @@ -548,7 +561,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 +3764,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('required'); + $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; +} diff --git a/mod/data/styles.css b/mod/data/styles.css index 955b3cdc7af..1985de42d12 100644 --- a/mod/data/styles.css +++ b/mod/data/styles.css @@ -68,3 +68,14 @@ .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 .privatefieldlocked { + font-style: italic; + color: #888888; +} +#page-mod-data-view .privatefieldhidden { + display: none; +} +#page-mod-data-edit .requiredfield { + color: #ff0000; +} diff --git a/mod/data/tests/behat/required_entries.feature b/mod/data/tests/behat/required_entries.feature new file mode 100644 index 00000000000..affecc4cb51 --- /dev/null +++ b/mod/data/tests/behat/required_entries.feature @@ -0,0 +1,113 @@ +@mod @mod_data +Feature: Users can be required to specify certain fields when adding entries to database activities + In order to populate databases + As a user + I need to specify certain fields when I add entries to databases + + Scenario: Students can add entries to a database + 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 | + | 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 | Option 1 | + 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 | 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 "Checkbox" field to "Test database name" database and I fill the form with: + | Field name | Not required Checkbox | + | Field description | Not required Checkbox | + | Options | 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 | 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 follow "Templates" + And I log out + 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 for otherwise empty | + And I press "Save and view" + Then ".alert.alert-error" "css_element" should exist in the "Required Checkbox" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Latlong" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Menu" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Number" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Radio" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Text input" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required Text area" "table_row" + Then ".alert.alert-error" "css_element" should exist in the "Required URL" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Checkbox" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Latlong" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Menu" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Number" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Radio" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Text input" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required Text area" "table_row" + Then ".alert.alert-error" "css_element" should not exist in the "Not required URL" "table_row" + And I follow "View list" + And I should see "No entries in database" diff --git a/mod/data/version.php b/mod/data/version.php index 369c277660a..8df231c70a9 100644 --- a/mod/data/version.php +++ b/mod/data/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2014111000; // The current module version (Date: YYYYMMDDXX) +$plugin->version = 2014111001; // 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; From 1c3b2058c8f82f63906c97b1a33ecf589fa7f320 Mon Sep 17 00:00:00 2001 From: John Okely Date: Tue, 17 Feb 2015 13:30:45 +0800 Subject: [PATCH 3/3] MDL-5583 mod_data: Improve required fields Fix accidental
in some field modify screens Update mod_data version Change required asterisk to image Improve required error message Fix required icon positions Remove required code from date field Add name in labels for fields Add required field option for multimenu Remove old required field title text modifier Add multimenu to behat Add more comprehensive behat tests Reload old input when an input error occurs Behat grammar fixes Allow location of 0, 0 Use html_writer Fix existing mod_data behat tests --- mod/data/db/install.xml | 4 +- mod/data/db/upgrade.php | 11 +- mod/data/edit.php | 2 +- mod/data/field.php | 4 +- mod/data/field/checkbox/field.class.php | 15 +- mod/data/field/date/field.class.php | 7 +- mod/data/field/file/field.class.php | 18 +-- mod/data/field/latlong/field.class.php | 38 +++-- mod/data/field/menu/field.class.php | 19 ++- mod/data/field/menu/mod.html | 1 - mod/data/field/multimenu/field.class.php | 35 ++++- mod/data/field/multimenu/mod.html | 4 + mod/data/field/picture/field.class.php | 23 +-- mod/data/field/picture/mod.html | 1 - mod/data/field/radiobutton/field.class.php | 34 +++-- mod/data/field/radiobutton/mod.html | 1 - mod/data/field/text/mod.html | 1 - mod/data/field/textarea/field.class.php | 36 +++-- mod/data/field/textarea/mod.html | 1 - mod/data/field/url/field.class.php | 19 ++- mod/data/lang/en/data.php | 3 +- mod/data/lib.php | 27 ++-- mod/data/styles.css | 11 +- mod/data/tests/behat/add_entries.feature | 8 +- mod/data/tests/behat/required_entries.feature | 141 +++++++++++++++--- mod/data/tests/behat/view_entries.feature | 6 +- mod/data/version.php | 2 +- 27 files changed, 303 insertions(+), 169 deletions(-) diff --git a/mod/data/db/install.xml b/mod/data/db/install.xml index aeddfb62e3f..a37bbb68bfe 100644 --- a/mod/data/db/install.xml +++ b/mod/data/db/install.xml @@ -1,5 +1,5 @@ - @@ -54,7 +54,7 @@ - + diff --git a/mod/data/db/upgrade.php b/mod/data/db/upgrade.php index d818ddbd616..02aa8f8810a 100644 --- a/mod/data/db/upgrade.php +++ b/mod/data/db/upgrade.php @@ -133,7 +133,11 @@ function xmldb_data_upgrade($oldversion) { // Moodle v2.7.0 release upgrade line. // Put any upgrade step following this. - if ($oldversion < 2014051201) { + + // Moodle v2.8.0 release upgrade line. + // Put any upgrade step following this. + + if ($oldversion < 2015022600) { // 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'); @@ -143,11 +147,8 @@ function xmldb_data_upgrade($oldversion) { $dbman->add_field($table, $field); } - upgrade_mod_savepoint(true, 2014051201, 'data'); + upgrade_mod_savepoint(true, 2015022600, 'data'); } - // Moodle v2.8.0 release upgrade line. - // Put any upgrade step following this. - return true; } diff --git a/mod/data/edit.php b/mod/data/edit.php index 7dc11db0a4d..7350ccad302 100644 --- a/mod/data/edit.php +++ b/mod/data/edit.php @@ -330,7 +330,7 @@ if ($data->addtemplate){ $errors .= $OUTPUT->notification($notification); } } - $replacements[] = $errors . $field->display_add_field($rid); + $replacements[] = $errors . $field->display_add_field($rid, $datarecord); } // Replace the field id tag. diff --git a/mod/data/field.php b/mod/data/field.php index 0258590034a..77e3a29eafa 100644 --- a/mod/data/field.php +++ b/mod/data/field.php @@ -266,11 +266,11 @@ if (($mode == 'new') && (!empty($newtype)) && confirm_sesskey()) { /// $table = new html_table(); $table->head = array( - get_string('fieldname','data'), + get_string('fieldname', 'data'), get_string('type', 'data'), get_string('required', 'data'), get_string('fielddescription', 'data'), - get_string('action','data'), + get_string('action', 'data'), ); $table->align = array('left','left','left', 'center'); $table->wrap = array(false,false,false,false); diff --git a/mod/data/field/checkbox/field.class.php b/mod/data/field/checkbox/field.class.php index 500dd2181c8..8b7c0a65330 100644 --- a/mod/data/field/checkbox/field.class.php +++ b/mod/data/field/checkbox/field.class.php @@ -27,7 +27,7 @@ class data_field_checkbox extends data_field_base { var $type = 'checkbox'; function display_add_field($recordid = 0, $formdata = null) { - global $CFG, $DB; + global $CFG, $DB, $OUTPUT; $content = array(); @@ -41,13 +41,18 @@ class data_field_checkbox extends data_field_base { $content = array(); } - $str = ''; + $str = '
'; + $str .= '
'.$this->field->name; if ($this->field->required) { - $str .= '
'; + $str .= '$nbsp;' . get_string('requiredelement', 'form'); + $str .= ''; + $str .= '
'; + $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'), + array('class' => 'req', 'title' => get_string('requiredelement', 'form'))); + $str .= '
'; } else { - $str .= '
'; + $str .= ''; } - $str .= '
'.$this->field->name.''; $i = 0; foreach (explode("\n", $this->field->param1) as $checkbox) { diff --git a/mod/data/field/date/field.class.php b/mod/data/field/date/field.class.php index 9361e31e773..fc5f4a94e45 100644 --- a/mod/data/field/date/field.class.php +++ b/mod/data/field/date/field.class.php @@ -51,12 +51,7 @@ class data_field_date extends data_field_base { $content = time(); } - $str = ''; - if ($this->field->required) { - $str .= '
'; - } else { - $str .= '
'; - } + $str = '
'; $dayselector = html_writer::select_time('days', 'field_'.$this->field->id.'_day', $content); $monthselector = html_writer::select_time('months', 'field_'.$this->field->id.'_month', $content); $yearselector = html_writer::select_time('years', 'field_'.$this->field->id.'_year', $content); diff --git a/mod/data/field/file/field.class.php b/mod/data/field/file/field.class.php index 567c852064e..b1cee2445ba 100644 --- a/mod/data/field/file/field.class.php +++ b/mod/data/field/file/field.class.php @@ -39,7 +39,7 @@ class data_field_file extends data_field_base { if ($formdata) { $fieldname = 'field_' . $this->field->id . '_file'; $itemid = $formdata->$fieldname; - } else if ($recordid){ + } 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); @@ -65,14 +65,18 @@ class data_field_file extends data_field_base { $itemid = file_get_unused_draft_itemid(); } - $html = ''; // database entry label + $html = '
'; + $html .= '
'.$this->field->name; + if ($this->field->required) { - $html .= '
'; + $html .= ' ' . get_string('requiredelement', 'form') . ''; + $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 .= '
'; + $html .= ''; } - $html .= '
'.$this->field->name.''; // itemid element $html .= ''; @@ -90,10 +94,6 @@ class data_field_file extends data_field_base { $output = $PAGE->get_renderer('core', 'files'); $html .= $output->render($fm); - - if ($this->field->required) { - $html .= '' . get_string('requiredfieldshort', 'data') . ''; - } $html .= '
'; $html .= '
'; diff --git a/mod/data/field/latlong/field.class.php b/mod/data/field/latlong/field.class.php index 47990c1e187..d89df71bdef 100644 --- a/mod/data/field/latlong/field.class.php +++ b/mod/data/field/latlong/field.class.php @@ -44,7 +44,7 @@ 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, $formdata = null) { - global $CFG, $DB; + global $CFG, $DB, $OUTPUT; $lat = ''; $long = ''; @@ -59,25 +59,26 @@ class data_field_latlong extends data_field_base { $long = $content->content1; } } - $str = ''; - if ($this->field->required) { - $str .= '
'; - } else { - $str .= '
'; - } + $str = '
'; $str .= '
'.$this->field->name.''; $str .= '
'; $str .= get_string('url','data').':'; @@ -73,6 +85,9 @@ 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); + if ($this->field->required) { + $str .= '' . get_string('requiredfieldshort', 'data') . ''; + } $str .= ''; return $str; } @@ -178,5 +193,3 @@ class data_field_url extends data_field_base { } } - - diff --git a/mod/data/field/url/mod.html b/mod/data/field/url/mod.html index e33b467c60f..afb5dc39026 100644 --- a/mod/data/field/url/mod.html +++ b/mod/data/field/url/mod.html @@ -11,6 +11,10 @@ field->param1) {echo 'checked="checked"';} ?> value="1" />
field->required?"checked=\"checked\"":""); ?>/>
field->param3) {echo 'checked="checked"';} ?> value="1" />
'; - $str .= ''; + $str .= ''; + $str .= html_writer::img($OUTPUT->pix_url('req'), get_string('requiredelement', 'form'), + array('class' => 'req', 'title' => get_string('requiredelement', 'form'))); } + $str .= ''; + $str .= ''; $str .= ''; $str .= '
'; - $str .= '°N
°E' . get_string('requiredfieldshort', 'data') . '°N
°E
'; $str .= ''; - if ($this->field->required) { - $str .= get_string('requiredfieldhint', 'data', s($this->field->description)); - } $str .= '
'; return $str; } @@ -240,4 +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 == ''); + } + } diff --git a/mod/data/field/menu/field.class.php b/mod/data/field/menu/field.class.php index d78b4caa73b..c53e3cb320d 100644 --- a/mod/data/field/menu/field.class.php +++ b/mod/data/field/menu/field.class.php @@ -32,18 +32,13 @@ class data_field_menu extends data_field_base { if ($formdata) { $fieldname = 'field_' . $this->field->id; $content = $formdata->$fieldname; - } else if ($recordid){ + } else if ($recordid) { $content = $DB->get_field('data_content', 'content', array('fieldid'=>$this->field->id, 'recordid'=>$recordid)); $content = trim($content); } else { $content = ''; } - $str = ''; - if ($this->field->required) { - $str .= '
'; - } else { - $str .= '
'; - } + $str = '
'; $options = array(); $rawoptions = explode("\n",$this->field->param1); @@ -54,11 +49,15 @@ 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 .= html_writer::select($options, 'field_'.$this->field->id, $content, array(''=>get_string('menuchoose', 'data')), array('id'=>'field_'.$this->field->id)); + $str .= ''; + $str .= html_writer::select($options, 'field_'.$this->field->id, $content, array(''=>get_string('menuchoose', 'data')), array('id'=>'field_'.$this->field->id)); $str .= '
'; diff --git a/mod/data/field/menu/mod.html b/mod/data/field/menu/mod.html index 62a4b018c29..e7c84e37cd4 100644 --- a/mod/data/field/menu/mod.html +++ b/mod/data/field/menu/mod.html @@ -7,7 +7,6 @@ - field->required?"checked=\"checked\"":""); ?>/> diff --git a/mod/data/field/multimenu/field.class.php b/mod/data/field/multimenu/field.class.php index 18f680d6769..75b6bc094d4 100644 --- a/mod/data/field/multimenu/field.class.php +++ b/mod/data/field/multimenu/field.class.php @@ -27,12 +27,16 @@ class data_field_multimenu extends data_field_base { var $type = 'multimenu'; function display_add_field($recordid = 0, $formdata = null) { - global $DB; + global $DB, $OUTPUT; if ($formdata) { $fieldname = 'field_' . $this->field->id; - $content = $formdata->$fieldname; - } else if ($recordid){ + 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 { @@ -41,10 +45,19 @@ class data_field_multimenu extends data_field_base { $str = '
'; $str .= ''; // hidden field - needed for empty selection - $str .= ''; + + $str .= ''; $str .= ' + + + field->required?"checked=\"checked\"":""); ?>/> + diff --git a/mod/data/field/picture/field.class.php b/mod/data/field/picture/field.class.php index 94a6e29b868..d4ade199637 100644 --- a/mod/data/field/picture/field.class.php +++ b/mod/data/field/picture/field.class.php @@ -40,6 +40,10 @@ class data_field_picture extends data_field_base { 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); @@ -67,13 +71,17 @@ class data_field_picture extends data_field_base { } else { $itemid = file_get_unused_draft_itemid(); } - $str = ''; + $str = '
'; + $str .= '
'.$this->field->name; + if ($this->field->required) { - $str .= '
'; + $str .= ' ' . get_string('requiredelement', 'form') . ''; + $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 .= '
'; + $str .= ''; } - $str .= '
'.$this->field->name.''; $str .= '
'; $str .= '
'; @@ -311,12 +316,12 @@ class data_field_picture extends data_field_base { function notemptyfield($value, $name) { global $USER; - $names = explode('_',$name); + $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 count($files) >= 2; } return false; } diff --git a/mod/data/field/picture/mod.html b/mod/data/field/picture/mod.html index 47cd7ab8cee..c00897676d8 100644 --- a/mod/data/field/picture/mod.html +++ b/mod/data/field/picture/mod.html @@ -12,7 +12,6 @@ - field->required?"checked=\"checked\"":""); ?>/> diff --git a/mod/data/field/radiobutton/field.class.php b/mod/data/field/radiobutton/field.class.php index 9ae2e2893fc..3008fb0f48b 100644 --- a/mod/data/field/radiobutton/field.class.php +++ b/mod/data/field/radiobutton/field.class.php @@ -27,30 +27,36 @@ class data_field_radiobutton extends data_field_base { var $type = 'radiobutton'; function display_add_field($recordid = 0, $formdata = null) { - global $CFG, $DB; + global $CFG, $DB, $OUTPUT; if ($formdata) { $fieldname = 'field_' . $this->field->id; - $content = $formdata->$fieldname; - } else if ($recordid){ + 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 = ''; + + $str = '
'; + $str .= '
' . $this->field->name; + if ($this->field->required) { - $str .= '
'; + $str .= ' ' . get_string('requiredelement', 'form') . ''; + $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 .= '
'; + $str .= ''; } - $str .= '
'.$this->field->name.''; $i = 0; $requiredstr = ''; - if ($this->field->required) { - $requiredstr = '' . get_string('requiredfieldshort', 'data') . ''; - } - $options = explode("\n",$this->field->param1); + $options = explode("\n", $this->field->param1); foreach ($options as $radio) { $radio = trim($radio); if ($radio === '') { @@ -66,11 +72,7 @@ class data_field_radiobutton extends data_field_base { $str .= '/>'; } - $str .= ''; - if ($i == count($options) - 1) { - $str .= $requiredstr; - } - $str .= '
'; + $str .= '
'; $i++; } $str .= '
'; diff --git a/mod/data/field/radiobutton/mod.html b/mod/data/field/radiobutton/mod.html index ebe8538f6e2..58db398ce34 100644 --- a/mod/data/field/radiobutton/mod.html +++ b/mod/data/field/radiobutton/mod.html @@ -7,7 +7,6 @@ - field->required?"checked=\"checked\"":""); ?>/> diff --git a/mod/data/field/text/mod.html b/mod/data/field/text/mod.html index fa104817053..597e7639a09 100644 --- a/mod/data/field/text/mod.html +++ b/mod/data/field/text/mod.html @@ -7,7 +7,6 @@ - field->required?"checked=\"checked\"":""); ?>/> diff --git a/mod/data/field/textarea/field.class.php b/mod/data/field/textarea/field.class.php index 442e8b5bb32..dda933ee3a9 100644 --- a/mod/data/field/textarea/field.class.php +++ b/mod/data/field/textarea/field.class.php @@ -54,12 +54,14 @@ class data_field_textarea extends data_field_base { $text = ''; $format = 0; - $str = ''; + $str = '
'; + $str .= '