Merge branch 'MDL-75498-master' of https://github.com/ferranrecio/moodle

This commit is contained in:
Andrew Nicols 2023-01-31 15:13:33 +08:00
commit 1f4794341b
30 changed files with 713 additions and 124 deletions

View File

@ -56,7 +56,7 @@ class template_editor_tools implements templatable, renderable {
public function export_for_template(\renderer_base $output): array {
$tools = [
$this->get_field_tags($this->templatename),
$this->get_field_id_tags($this->templatename),
$this->get_field_info_tags($this->templatename),
$this->get_action_tags($this->templatename),
$this->get_other_tags($this->templatename),
];
@ -90,29 +90,30 @@ class template_editor_tools implements templatable, renderable {
$fieldname = $field->get_name();
$taglist["[[$fieldname]]"] = $fieldname;
}
$taglist['##otherfields##'] = get_string('otherfields', 'data');
return $this->get_optgroup_data($name, $taglist);
}
/**
* Return the field IDs template tags.
* Return the field information template tags.
*
* @param string $templatename the template name
* @return array|null array of tags.
*/
protected function get_field_id_tags(string $templatename): array {
$name = get_string('fieldids', 'data');
if ($templatename != 'addtemplate') {
return $this->get_optgroup_data($name, []);
}
protected function get_field_info_tags(string $templatename): array {
$name = get_string('fieldsinformationtags', 'data');
$taglist = [];
// Field IDs.
$fields = $this->manager->get_fields();
foreach ($fields as $field) {
if ($field->type === 'unknown') {
continue;
}
$fieldname = $field->get_name();
$taglist["[[$fieldname#id]]"] = "$fieldname id";
if ($templatename == 'addtemplate') {
$taglist["[[$fieldname#id]]"] = get_string('fieldtagid', 'mod_data', $fieldname);
}
$taglist["[[$fieldname#name]]"] = get_string('fieldtagname', 'mod_data', $fieldname);
$taglist["[[$fieldname#description]]"] = get_string('fieldtagdescription', 'mod_data', $fieldname);
}
return $this->get_optgroup_data($name, $taglist);
}
@ -129,11 +130,11 @@ class template_editor_tools implements templatable, renderable {
return $this->get_optgroup_data($name, []);
}
$taglist = [
'##actionsmenu##' => get_string('actionsmenu', 'data'),
'##edit##' => get_string('edit', 'data'),
'##delete##' => get_string('delete', 'data'),
'##approve##' => get_string('approve', 'data'),
'##disapprove##' => get_string('disapprove', 'data'),
'##actionsmenu##' => get_string('actionsmenu', 'data'),
];
if ($templatename != 'rsstemplate') {
$taglist['##export##'] = get_string('export', 'data');

View File

@ -19,6 +19,7 @@ namespace mod_data;
use action_menu;
use action_menu_link_secondary;
use core\output\checkbox_toggleall;
use data_field_base;
use html_writer;
use mod_data\manager;
use moodle_url;
@ -79,6 +80,9 @@ class template {
/** @var array The mod_data fields. */
protected $fields = [];
/** @var array All fields that are not present in the template content. */
protected $otherfields = [];
/**
* Class contructor.
*
@ -213,6 +217,13 @@ class template {
return;
}
$this->tags = $matches['tags'];
// Check if some tag require some extra template scan.
foreach ($this->tags as $tagname) {
$methodname = "preprocess_tag_{$tagname}";
if (method_exists($this, $methodname)) {
$this->$methodname($templatecontent);
}
}
}
/**
@ -309,9 +320,13 @@ class template {
$this->search,
$field->display_browse_field($entry->id, $this->templatename)
);
// Field id.
// Other dynamic field information.
$pattern = '[[' . $field->field->name . '#id]]';
$result[$pattern] = $field->field->id;
$pattern = '[[' . $field->field->name . '#name]]';
$result[$pattern] = $field->field->name;
$pattern = '[[' . $field->field->name . '#description]]';
$result[$pattern] = $field->field->description;
}
return $result;
}
@ -707,6 +722,46 @@ class template {
return (string) $entry->id;
}
/**
* Prepare otherfield tag scanning the present template fields.
*
* @param string $templatecontent the template content
*/
protected function preprocess_tag_otherfields(string $templatecontent) {
$otherfields = [];
$fields = $this->manager->get_fields();
foreach ($fields as $field) {
if (strpos($templatecontent, "[[" . $field->field->name . "]]") === false) {
$otherfields[] = $field;
}
}
$this->otherfields = $otherfields;
}
/**
* Returns the ##otherfields## tag replacement for an entry.
*
* @param stdClass $entry the entry object
* @param bool $canmanageentry if the current user can manage this entry
* @return string the tag replacement
*/
protected function get_tag_otherfields_replacement(stdClass $entry, bool $canmanageentry): string {
global $OUTPUT;
$fields = [];
foreach ($this->otherfields as $field) {
$fieldvalue = highlight(
$this->search,
$field->display_browse_field($entry->id, $this->templatename)
);
$fieldinfo = [
'fieldname' => $field->field->name,
'fieldcontent' => $fieldvalue,
];
$fields[] = $fieldinfo;
}
return $OUTPUT->render_from_template('mod_data/fields_otherfields', ['fields' => $fields]);
}
/**
* Returns the ##actionsmenu## tag replacement for an entry.
*
@ -842,6 +897,8 @@ class template {
?int $entryid = null,
?stdClass $entrydata = null
): string {
global $OUTPUT;
$manager = $this->manager;
$renderer = $manager->get_renderer();
$templatecontent = $this->templatecontent;
@ -864,34 +921,38 @@ class template {
$replacements = [];
// Then we generate strings to replace.
$otherfields = [];
foreach ($possiblefields as $field) {
// To skip unnecessary calls to display_add_field().
$fieldinput = $this->get_field_input($processeddata, $entryid, $entrydata, $field);
if (strpos($templatecontent, "[[" . $field->field->name . "]]") !== false) {
// Replace the field tag.
$patterns[] = "[[" . $field->field->name . "]]";
$errors = '';
$fieldnotifications = $processeddata->fieldnotifications[$field->field->name] ?? [];
if (!empty($fieldnotifications)) {
foreach ($fieldnotifications as $notification) {
$errors .= $renderer->notification($notification);
}
}
$fielddisplay = '';
if ($field->type === 'unknown') {
if ($this->canmanageentries) { // Display notification for users that can manage entries.
$errors .= $renderer->notification(get_string('missingfieldtype', 'data',
(object)['name' => $field->field->name]));
}
} else {
$fielddisplay = $field->display_add_field($entryid, $entrydata);
}
$replacements[] = $errors . $fielddisplay;
$replacements[] = $fieldinput;
} else {
// Is in another fields.
$otherfields[] = [
'fieldname' => $field->field->name,
'fieldcontent' => $fieldinput,
];
}
// Replace the field id tag.
$patterns[] = "[[" . $field->field->name . "#id]]";
$replacements[] = 'field_' . $field->field->id;
$patterns[] = '[[' . $field->field->name . '#name]]';
$replacements[] = $field->field->name;
$patterns[] = '[[' . $field->field->name . '#description]]';
$replacements[] = $field->field->description;
}
$patterns[] = "##otherfields##";
if (!empty($otherfields)) {
$replacements[] = $OUTPUT->render_from_template(
'mod_data/fields_otherfields',
['fields' => $otherfields]
);
} else {
$replacements[] = '';
}
if (core_tag_tag::is_enabled('mod_data', 'data_records')) {
@ -902,4 +963,42 @@ class template {
$result .= str_ireplace($patterns, $replacements, $templatecontent);
return $result;
}
/**
* Return the input form html from a specific field.
*
* @param stdClass $processeddata the previous process data information.
* @param int|null $entryid the possible entry id
* @param stdClass|null $entrydata the entry data from a previous form or from a real entry
* @param data_field_base $field the field object
* @return string the add entry HTML content
*/
private function get_field_input(
stdClass $processeddata,
?int $entryid = null,
?stdClass $entrydata = null,
data_field_base $field
): string {
$renderer = $this->manager->get_renderer();
$errors = '';
$fieldnotifications = $processeddata->fieldnotifications[$field->field->name] ?? [];
if (!empty($fieldnotifications)) {
foreach ($fieldnotifications as $notification) {
$errors .= $renderer->notification($notification);
}
}
$fielddisplay = '';
if ($field->type === 'unknown') {
if ($this->canmanageentries) { // Display notification for users that can manage entries.
$errors .= $renderer->notification(get_string(
'missingfieldtype',
'data',
(object)['name' => $field->field->name]
));
}
} else {
$fielddisplay = $field->display_add_field($entryid, $entrydata);
}
return $errors . $fielddisplay;
}
}

View File

@ -178,7 +178,6 @@ $string['fieldenclosure'] = 'Field enclosure';
$string['fieldheight'] = 'Height';
$string['fieldheightlistview'] = 'Height (in pixels) in list view';
$string['fieldheightsingleview'] = 'Height (in pixels) in single view';
$string['fieldids'] = 'Field ids';
$string['fieldmappings'] = 'Field mappings';
$string['fieldmappings_help'] = 'This menu allows you to keep the data from the existing database. To preserve the data in a field, you must map it to a new field, where the data will appear. Any field can also be left blank, with no information copied into it. Any old field not mapped to a new one will be lost and all its data removed.
You can only map fields of the same type, so each drop-down menu will have different fields in it. Also, you must be careful not to try and map one old field to more than one new field.';
@ -188,7 +187,11 @@ $string['fieldnotmatched'] = 'The following fields in your file are not known in
$string['fieldoptions'] = 'Options (one per line)';
$string['fields'] = 'Fields';
$string['fieldshelp'] = 'Create fields to collect different types of data. Fields define the structure of the entries in your database.';
$string['fieldsinformationtags'] = 'Field information';
$string['fieldsnavigation'] = 'Fields tertiary navigation';
$string['fieldtagdescription'] = '{$a} description';
$string['fieldtagname'] = '{$a} name';
$string['fieldtagid'] = '{$a} id';
$string['fieldupdated'] = 'Field updated';
$string['fieldwidth'] = 'Width';
$string['fieldwidthlistview'] = 'Width (in pixels) in list view';
@ -336,6 +339,7 @@ $string['openafterclose'] = 'You have specified an open date after the close dat
$string['optionaldescription'] = 'Short description (optional)';
$string['optionalfilename'] = 'Filename (optional)';
$string['other'] = 'Other';
$string['otherfields'] = 'All other fields';
$string['overwrite'] = 'Overwrite';
$string['overrwritedesc'] = 'Replace existing preset with this name and overwrite its contents';
$string['overwritesettings'] = 'Overwrite current settings such as comments, ratings, etc.';
@ -484,3 +488,6 @@ $string['savetemplate'] = 'Save template';
$string['addedby'] = 'Added by';
$string['addentries'] = 'Add entries';
$string['todatabase'] = 'to this database.';
// Deprecated since Moodle 4.2.
$string['fieldids'] = 'Field ids';

View File

@ -8,4 +8,4 @@ savetemplate,mod_data
addedby,mod_data
addentries,mod_data
todatabase,mod_data
fieldids,mod_data

View File

@ -826,34 +826,35 @@ function data_generate_tag_form($recordid = false, $selected = []) {
function data_replace_field_in_templates($data, $searchfieldname, $newfieldname) {
global $DB;
if (!empty($newfieldname)) {
$prestring = '[[';
$poststring = ']]';
$idpart = '#id';
} else {
$prestring = '';
$poststring = '';
$idpart = '';
$newdata = (object)['id' => $data->id];
$update = false;
$templates = ['listtemplate', 'singletemplate', 'asearchtemplate', 'addtemplate', 'rsstemplate'];
foreach ($templates as $templatename) {
if (empty($data->$templatename)) {
continue;
}
$search = [
'[[' . $searchfieldname . ']]',
'[[' . $searchfieldname . '#id]]',
'[[' . $searchfieldname . '#name]]',
'[[' . $searchfieldname . '#description]]',
];
if (empty($newfieldname)) {
$replace = ['', '', '', ''];
} else {
$replace = [
'[[' . $newfieldname . ']]',
'[[' . $newfieldname . '#id]]',
'[[' . $newfieldname . '#name]]',
'[[' . $newfieldname . '#description]]',
];
}
$newdata->{$templatename} = str_ireplace($search, $replace, $data->{$templatename} ?? '');
$update = true;
}
if (!$update) {
return true;
}
$newdata = new stdClass();
$newdata->id = $data->id;
$newdata->singletemplate = str_ireplace('[['.$searchfieldname.']]',
$prestring.$newfieldname.$poststring, $data->singletemplate ?? '');
$newdata->listtemplate = str_ireplace('[['.$searchfieldname.']]',
$prestring.$newfieldname.$poststring, $data->listtemplate ?? '');
$newdata->addtemplate = str_ireplace('[['.$searchfieldname.']]',
$prestring.$newfieldname.$poststring, $data->addtemplate ?? '');
$newdata->addtemplate = str_ireplace('[['.$searchfieldname.'#id]]',
$prestring.$newfieldname.$idpart.$poststring, $data->addtemplate ?? '');
$newdata->rsstemplate = str_ireplace('[['.$searchfieldname.']]',
$prestring.$newfieldname.$poststring, $data->rsstemplate ?? '');
return $DB->update_record('data', $newdata);
}
@ -864,29 +865,36 @@ function data_replace_field_in_templates($data, $searchfieldname, $newfieldname)
* @global object
* @param object $data
* @param string $newfieldname
* @return bool if the field has been added or not
*/
function data_append_new_field_to_templates($data, $newfieldname) {
global $DB;
function data_append_new_field_to_templates($data, $newfieldname): bool {
global $DB, $OUTPUT;
$newdata = new stdClass();
$newdata->id = $data->id;
$change = false;
if (!empty($data->singletemplate)) {
$newdata->singletemplate = $data->singletemplate.' [[' . $newfieldname .']]';
$change = true;
$newdata = (object)['id' => $data->id];
$update = false;
$templates = ['singletemplate', 'addtemplate', 'rsstemplate'];
foreach ($templates as $templatename) {
if (empty($data->$templatename)
|| strpos($data->$templatename, "[[$newfieldname]]") !== false
|| strpos($data->$templatename, "##otherfields##") !== false
) {
continue;
}
$newdata->$templatename = $data->$templatename;
$fields = [[
'fieldname' => '[[' . $newfieldname . '#name]]',
'fieldcontent' => '[[' . $newfieldname . ']]',
]];
$newdata->$templatename .= $OUTPUT->render_from_template(
'mod_data/fields_otherfields',
['fields' => $fields, 'classes' => 'added_field']
);
$update = true;
}
if (!empty($data->addtemplate)) {
$newdata->addtemplate = $data->addtemplate.' [[' . $newfieldname . ']]';
$change = true;
}
if (!empty($data->rsstemplate)) {
$newdata->rsstemplate = $data->singletemplate.' [[' . $newfieldname . ']]';
$change = true;
}
if ($change) {
$DB->update_record('data', $newdata);
if (!$update) {
return false;
}
return $DB->update_record('data', $newdata);
}
@ -1673,7 +1681,7 @@ function mod_data_rating_can_see_item_ratings($params) {
* @return void
*/
function data_print_preference_form($data, $perpage, $search, $sort='', $order='ASC', $search_array = '', $advanced = 0, $mode= ''){
global $CFG, $DB, $PAGE, $OUTPUT;
global $DB, $PAGE, $OUTPUT;
$cm = get_coursemodule_from_instance('data', $data->id);
$context = context_module::instance($cm->id);
@ -1802,21 +1810,45 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order='
$replacement = array();
// Then we generate strings to replace for normal tags
$otherfields = [];
foreach ($fields as $field) {
$fieldname = $field->field->name;
$fieldname = preg_quote($fieldname, '/');
$patterns[] = "/\[\[$fieldname\]\]/i";
$searchfield = data_get_field_from_id($field->field->id, $data);
if ($searchfield->type === 'unknown') {
continue;
}
if (!empty($search_array[$field->field->id]->data)) {
$replacement[] = $searchfield->display_search_field($search_array[$field->field->id]->data);
$searchinput = $searchfield->display_search_field($search_array[$field->field->id]->data);
} else {
$replacement[] = $searchfield->display_search_field();
$searchinput = $searchfield->display_search_field();
}
$patterns[] = "/\[\[$fieldname\]\]/i";
$replacement[] = $searchinput;
// Extra field information.
$patterns[] = "/\[\[$fieldname#name\]\]/i";
$replacement[] = $field->field->name;
$patterns[] = "/\[\[$fieldname#description\]\]/i";
$replacement[] = $field->field->description;
// Other fields.
if (strpos($asearchtemplate, "[[" . $field->field->name . "]]") === false) {
$otherfields[] = [
'fieldname' => $searchfield->field->name,
'fieldcontent' => $searchinput,
];
}
}
$patterns[] = "/##otherfields##/";
if (!empty($otherfields)) {
$replacement[] = $OUTPUT->render_from_template(
'mod_data/fields_otherfields',
['fields' => $otherfields]
);
} else {
$replacement[] = '';
}
$fn = !empty($search_array[DATA_FIRSTNAME]->data) ? $search_array[DATA_FIRSTNAME]->data : '';
$ln = !empty($search_array[DATA_LASTNAME]->data) ? $search_array[DATA_LASTNAME]->data : '';
$patterns[] = '/##firstname##/';

View File

@ -1,14 +1,15 @@
<div class="imagegallery-addentry">
<div class="form-group">
<div class="font-weight-bold">Title</div>
<div class="font-weight-bold">[[title#name]]</div>
[[title]]
</div>
<div class="form-group">
<div class="font-weight-bold">Image</div>
<div class="font-weight-bold">[[image#name]]</div>
[[image]]
</div>
<div class="form-group">
<div class="font-weight-bold">Description</div>
<div class="font-weight-bold">[[description#name]]</div>
[[description]]
</div>
##otherfields##
</div>

View File

@ -10,11 +10,11 @@
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Title</div>
<div class="font-weight-bold mb-2">[[title#name]]</div>
[[title]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Description</div>
<div class="font-weight-bold mb-2">[[description#name]]</div>
[[description]]
</div>
</div>

View File

@ -27,5 +27,6 @@
<div class="row singleentry-image">
<div class="col">[[image]]</div>
</div>
##otherfields##
</div>
</div>

View File

@ -90,3 +90,29 @@ Feature: Users can use the Image gallery preset
And I press "Save"
Then I should see "New image"
And I should see "This is the description for the new image."
@javascript
Scenario: Image gallery. Renaming a field should affect the template
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
And I navigate to "Fields" in current page administration
And I open the action menu in "title" "table_row"
And I choose "Edit" in the open action menu
And I set the field "Field name" to "Edited field name"
And I press "Save"
And I should see "Field updated"
When I navigate to "Database" in current page administration
Then I click on "Advanced search" "checkbox"
And I should see "Edited field name"
And I click on "Add entry" "button"
And I should see "Edited field name"
@javascript
Scenario: Image gallery. Has otherfields tag
Given the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Extra field | Test field description |
And I am on the "Mountain landscapes" "data activity" page logged in as teacher1
When I select "Single view" from the "jump" singleselect
Then I should see "Extra field"
And I click on "Add entry" "button"
And I should see "Extra field"

View File

@ -1,10 +1,11 @@
<div class="journal-addentry">
<div class="form-group">
<div class="font-weight-bold">Title</div>
<div class="font-weight-bold">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group">
<div class="font-weight-bold">Content</div>
<div class="font-weight-bold">[[Content#name]]</div>
[[Content]]
</div>
##otherfields##
</div>

View File

@ -10,12 +10,12 @@
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Title</div>
[[title]]
<div class="font-weight-bold mb-2">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Content</div>
[[content]]
<div class="font-weight-bold mb-2">[[Content#name]]</div>
[[Content]]
</div>
</div>
</div>

View File

@ -24,5 +24,6 @@
<div class="singleentry-content">
[[Content]]
</div>
##otherfields##
</div>
</div>

View File

@ -76,3 +76,27 @@ Feature: Users can use the Journal preset
And I press "Save"
Then I should see "This is the title"
And I should see "This is the content for the new entry."
@javascript
Scenario: Journal. Renaming a field should affect the template
Given I am on the "Student reflections" "data activity" page logged in as teacher1
And I navigate to "Fields" in current page administration
And I open the action menu in "Content" "table_row"
And I choose "Edit" in the open action menu
And I set the field "Field name" to "Edited field name"
And I press "Save"
And I should see "Field updated"
When I navigate to "Database" in current page administration
Then I click on "Advanced search" "checkbox"
And I should see "Edited field name"
And I click on "Add entry" "button"
And I should see "Edited field name"
@javascript
Scenario: Journal. Has otherfields tag
Given the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Extra field | Test field description |
And I am on the "Student reflections" "data activity" page logged in as teacher1
When I click on "Add entry" "button"
Then I should see "Extra field"

View File

@ -1,18 +1,19 @@
<div class="proposals-addentry">
<div class="form-group">
<div class="font-weight-bold">Title</div>
<div class="font-weight-bold">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group">
<div class="font-weight-bold">Status</div>
<div class="font-weight-bold">[[Status#name]]</div>
[[Status]]
</div>
<div class="form-group">
<div class="font-weight-bold">Summary</div>
<div class="font-weight-bold">[[Summary#name]]</div>
[[Summary]]
</div>
<div class="form-group">
<div class="font-weight-bold">Content</div>
<div class="font-weight-bold">[[Content#name]]</div>
[[Content]]
</div>
##otherfields##
</div>

View File

@ -10,19 +10,19 @@
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Title</div>
<div class="font-weight-bold mb-2">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Status</div>
<div class="font-weight-bold mb-2">[[Status#name]]</div>
[[Status]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Summary</div>
<div class="font-weight-bold mb-2">[[Summary#name]]</div>
[[Summary]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Content</div>
<div class="font-weight-bold mb-2">[[Content#name]]</div>
[[Content]]
</div>
</div>

View File

@ -21,18 +21,18 @@
<div class="proposals-single-body">
<div class="row my-3">
<div class="col-3 col-md-1"><strong>Status</strong></div>
<div class="col-3 col-md-1"><strong>[[Status#name]]</strong></div>
<div class="col">[[Status]]</div>
</div>
<div class="row singleentry-summary">
<div class="col">
<h3 class="my-5">Summary</h3>
<h3 class="my-5">[[Summary#name]]</h3>
[[Summary]]
</div>
</div>
<div class="row singleentry-content">
<div class="col">
<h3 class="my-5">Content</h3>
<h3 class="my-5">[[Content#name]]</h3>
[[Content]]
</div>
</div>

View File

@ -23,21 +23,22 @@
<div class="proposals-single-body">
<div class="row singleentry-status">
<div class="col">
<h3 class="my-5">Status</h3>
<h3 class="my-5">[[Status#name]]</h3>
[[Status]]
</div>
</div>
<div class="row singleentry-summary">
<div class="col">
<h3 class="my-5">Summary</h3>
<h3 class="my-5">[[Summary#name]]</h3>
[[Summary]]
</div>
</div>
<div class="row singleentry-content">
<div class="col">
<h3 class="my-5">Content</h3>
<h3 class="my-5">[[Content#name]]</h3>
[[Content]]
</div>
</div>
##otherfields##
</div>
</div>

View File

@ -94,3 +94,31 @@ Feature: Users can use the Proposals preset
And I should see "Approved"
And I should see "This is the summary for the new entry."
And I should see "This is the content for the new entry."
@javascript
Scenario: Proposals. Renaming a field should affect the template
Given I am on the "Student projects" "data activity" page logged in as teacher1
And I navigate to "Fields" in current page administration
And I open the action menu in "Summary" "table_row"
And I choose "Edit" in the open action menu
And I set the field "Field name" to "Edited field name"
And I press "Save"
And I should see "Field updated"
When I navigate to "Database" in current page administration
Then I click on "Advanced search" "checkbox"
And I should see "Edited field name"
And I select "Single view" from the "jump" singleselect
And I should see "Edited field name"
And I click on "Add entry" "button"
And I should see "Edited field name"
@javascript
Scenario: Proposals. Has otherfields tag
Given the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Extra field | Test field description |
And I am on the "Student projects" "data activity" page logged in as teacher1
When I select "Single view" from the "jump" singleselect
Then I should see "Extra field"
And I click on "Add entry" "button"
And I should see "Extra field"

View File

@ -1,6 +1,6 @@
<div class="resources-addentry">
<div class="form-group">
<div class="font-weight-bold">Title</div>
<div class="font-weight-bold">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group">
@ -8,7 +8,7 @@
[[Author]]
</div>
<div class="form-group">
<div class="font-weight-bold">Cover</div>
<div class="font-weight-bold">[[Cover#name]]</div>
[[Cover]]
</div>
<div class="form-group">
@ -16,11 +16,12 @@
[[Description]]
</div>
<div class="form-group">
<div class="font-weight-bold">Web link</div>
<div class="font-weight-bold">[[Web link#name]]</div>
[[Web link]]
</div>
<div class="form-group">
<div class="font-weight-bold">Type</div>
<div class="font-weight-bold">[[Type#name]]</div>
[[Type]]
</div>
##otherfields##
</div>

View File

@ -10,7 +10,7 @@
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Title</div>
<div class="font-weight-bold mb-2">[[Title#name]]</div>
[[Title]]
</div>
<div class="form-group col">
@ -22,11 +22,11 @@
[[Description]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Link</div>
<div class="font-weight-bold mb-2">[[Web link#name]]</div>
[[Web link]]
</div>
<div class="form-group col">
<div class="font-weight-bold mb-2">Type</div>
<div class="font-weight-bold mb-2">[[Type#name]]</div>
[[Type]]
</div>
</div>

View File

@ -27,7 +27,7 @@
<div class="col-9 col-md-11">[[Author]]</div>
</div>
<div class="row my-3">
<div class="col-3 col-md-1"><strong>Type</strong></div>
<div class="col-3 col-md-1"><strong>[[Type#name]]</strong></div>
<div class="col-9 col-md-11">[[Type]]</div>
</div>
<div class="row my-3">

View File

@ -28,7 +28,7 @@
<div class="col-9 col-md-auto">[[Author]]</div>
</div>
<div class="row my-3">
<div class="col-3 col-md-2 font-weight-bold">Type</div>
<div class="col-3 col-md-2 font-weight-bold">[[Type#name]]</div>
<div class="col-9 col-md-auto">[[Type]]</div>
</div>
<div class="row my-3">
@ -45,5 +45,6 @@
[[Description]]
</div>
</div>
##otherfields##
</div>
</div>

View File

@ -99,3 +99,29 @@ Feature: Users can use the Resources preset
And I should see "This is the author"
And I should see "https://thisisthelink.cat"
And I should see "Type2"
@javascript
Scenario: Resources. Renaming a field should affect the template
Given I am on the "Student resources" "data activity" page logged in as teacher1
And I navigate to "Fields" in current page administration
And I open the action menu in "Type" "table_row"
And I choose "Edit" in the open action menu
And I set the field "Field name" to "Edited field name"
And I press "Save"
And I should see "Field updated"
When I navigate to "Database" in current page administration
Then I click on "Advanced search" "checkbox"
And I should see "Edited field name"
And I click on "Add entry" "button"
And I should see "Edited field name"
@javascript
Scenario: Resources. Has otherfields tag
Given the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | Extra field | Test field description |
And I am on the "Student resources" "data activity" page logged in as teacher1
When I select "Single view" from the "jump" singleselect
Then I should see "Extra field"
And I click on "Add entry" "button"
And I should see "Extra field"

View File

@ -40,6 +40,7 @@
{{{fieldcontent}}}
</div>
{{/fields}}
##otherfields##
{{#tags}}
<div class="form-group pt-3">
<div class="font-weight-bold">{{#str}}tags{{/str}}</div>

View File

@ -61,6 +61,7 @@
<p class="mt-2">{{fieldcontent}}</p>
</div>
{{/fields}}
##otherfields##
{{#tags}}
<div class="mt-4">
<span class="font-weight-bold">{{#str}}tags{{/str}}</span>

View File

@ -0,0 +1,33 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_data/fields_otherfields
The ##otherfields## template.
Example context (json):
{
"fieldname": "This is the field name",
"fieldcontent": "This is the field name",
"classes": "added_fields"
}
}}
<div class="{{^classes}}tag_otherfields{{/classes}} {{#classes}}{{classes}}{{/classes}}">
{{#fields}}
<div class="mt-4">
<span class="font-weight-bold">{{fieldname}}</span>
<p class="mt-2">{{{fieldcontent}}}</p>
</div>
{{/fields}}
</div>

View File

@ -0,0 +1,82 @@
@mod @mod_data
Feature: Database entries can be searched using an advanced search form.
In order to find an entry
As a user
I need to have an advanced search form
Background:
Given the following "users" exist:
| username | firstname | lastname | email |
| teacher1 | Teacher | 1 | teacher1@example.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 |
And the following "activities" exist:
| activity | name | intro | course | idnumber |
| data | Test database name | n | C1 | data1 |
And the following "mod_data > fields" exist:
| database | type | name | description |
| data1 | text | My Field | Field 1 description |
| data1 | text | Their field | Field 2 description |
And the following "mod_data > entries" exist:
| database | user | My Field | Their field |
| data1 | teacher1 | First content | Owned content |
| data1 | teacher1 | Second content | Authored content |
And I am on the "Test database name" "data activity" page logged in as teacher1
And I should see "First content"
And I should see "Second content"
@javascript
Scenario: Content can be searched using advanced search
Given I click on "Advanced search" "checkbox"
And I should see "My Field" in the "data_adv_form" "region"
And I should see "Their field" in the "data_adv_form" "region"
When I set the field "My Field" to "First"
And I click on "Save settings" "button" in the "data_adv_form" "region"
Then I should see "First content"
And I should not see "Second content"
@javascript
Scenario: Advanced search template can use field information tags
Given I navigate to "Templates" in current page administration
And I set the field "Templates tertiary navigation" to "Advanced search template"
And I set the following fields to these values:
| Advanced search template | The test is on [[My Field#name]], [[My Field#description]], and the input [[My Field]] |
And I click on "Save" "button" in the "sticky-footer" "region"
And I navigate to "Database" in current page administration
And I should see "First content"
And I should see "Second content"
And I click on "Advanced search" "checkbox"
And I should see "The test is on My Field, Field 1 description, and the input" in the "data_adv_form" "region"
And I should not see "Their field" in the "data_adv_form" "region"
When I set the field "My Field" to "First"
And I click on "Save settings" "button" in the "data_adv_form" "region"
Then I should see "First content"
And I should not see "Second content"
@javascript
Scenario: Advanced search can use otherfields tag
Given I navigate to "Templates" in current page administration
And I set the field "Templates tertiary navigation" to "Advanced search template"
And I set the following fields to these values:
| Advanced search template | Main search [[My Field]], Other fields ##otherfields## |
And I click on "Save" "button" in the "sticky-footer" "region"
And I navigate to "Database" in current page administration
And I should see "First content"
And I should see "Second content"
And I click on "Advanced search" "checkbox"
And I should see "Main search" in the "data_adv_form" "region"
And I should see "Other fields" in the "data_adv_form" "region"
And I should see "Their field" in the "data_adv_form" "region"
When I set the field "My Field" to "First"
And I click on "Save settings" "button" in the "data_adv_form" "region"
Then I should see "First content"
And I should not see "Second content"
And I set the field "My Field" to ""
And I set the field "Their field" to "Authored content"
And I click on "Save settings" "button" in the "data_adv_form" "region"
And I should not see "First content"
And I should see "Second content"

View File

@ -2039,4 +2039,130 @@ class lib_test extends \advanced_testcase {
$this->assertNotEmpty($activity->{$template});
}
}
/**
* Test for data_replace_field_in_templates().
*
* @covers ::data_replace_field_in_templates
*/
public function test_data_replace_field_in_templates(): void {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$course = $this->getDataGenerator()->create_course();
$templatecontent = "Field [[myfield]], [[myfield#id]], [[myfield#name]], [[myfield#description]], ";
$params = ['course' => $course];
foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) {
$params[$templatename] = $templatecontent;
}
$activity = $this->getDataGenerator()->create_module(manager::MODULE, $params);
$generator = $this->getDataGenerator()->get_plugin_generator(manager::PLUGINNAME);
$fieldrecord = (object)['name' => 'myfield', 'type' => 'text', 'description' => 'This is a field'];
$generator->create_field($fieldrecord, $activity);
data_replace_field_in_templates($activity, 'myfield', 'newfieldname');
$dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]);
$newcontent = "Field [[newfieldname]], [[newfieldname#id]], [[newfieldname#name]], [[newfieldname#description]], ";
// Field compatible templates.
$this->assertEquals($newcontent, $dbactivity->listtemplate);
$this->assertEquals($newcontent, $dbactivity->singletemplate);
$this->assertEquals($newcontent, $dbactivity->asearchtemplate);
$this->assertEquals($newcontent, $dbactivity->addtemplate);
$this->assertEquals($newcontent, $dbactivity->rsstemplate);
// Other templates.
$this->assertEquals($templatecontent, $dbactivity->listtemplateheader);
$this->assertEquals($templatecontent, $dbactivity->listtemplatefooter);
$this->assertEquals($templatecontent, $dbactivity->csstemplate);
$this->assertEquals($templatecontent, $dbactivity->jstemplate);
$this->assertEquals($templatecontent, $dbactivity->rsstitletemplate);
}
/**
* Test for data_append_new_field_to_templates().
*
* @covers ::data_append_new_field_to_templates
* @dataProvider data_append_new_field_to_templates_provider
* @param bool $hasfield if the field is present in the templates
* @param bool $hasotherfields if the field is not present in the templates
* @param bool $expected the expected return
*/
public function test_data_append_new_field_to_templates(bool $hasfield, bool $hasotherfields, bool $expected) {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$templatecontent = "Template content";
if ($hasfield) {
$templatecontent .= "Has [[myfield]].";
}
if ($hasotherfields) {
$templatecontent .= "And also ##otherfields##.";
}
$course = $this->getDataGenerator()->create_course();
$params = ['course' => $course];
foreach (manager::TEMPLATES_LIST as $templatename => $templatefile) {
$params[$templatename] = $templatecontent;
}
$activity = $this->getDataGenerator()->create_module(manager::MODULE, $params);
$result = data_append_new_field_to_templates($activity, 'myfield');
$this->assertEquals($expected, $result);
// Check fields with auto add fields.
$dbactivity = $DB->get_record(manager::MODULE, ['id' => $activity->id]);
if ($hasfield || $hasotherfields) {
$this->assertEquals($dbactivity->singletemplate, $templatecontent);
$this->assertEquals($dbactivity->addtemplate, $templatecontent);
$this->assertEquals($dbactivity->rsstemplate, $templatecontent);
} else {
$regexp = '|Template content.*\[\[myfield\]\]|';
// We don't want line breaks for the validations.
$this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->singletemplate));
$this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->addtemplate));
$this->assertMatchesRegularExpression($regexp, str_replace("\n", '', $dbactivity->rsstemplate));
}
// No auto add field templates.
$this->assertEquals($dbactivity->asearchtemplate, $templatecontent);
$this->assertEquals($dbactivity->listtemplate, $templatecontent);
$this->assertEquals($dbactivity->listtemplateheader, $templatecontent);
$this->assertEquals($dbactivity->listtemplatefooter, $templatecontent);
$this->assertEquals($dbactivity->csstemplate, $templatecontent);
$this->assertEquals($dbactivity->jstemplate, $templatecontent);
$this->assertEquals($dbactivity->rsstitletemplate, $templatecontent);
}
/**
* Data provider for test_data_append_new_field_to_templates().
*
* @return array of scenarios
*/
public function data_append_new_field_to_templates_provider(): array {
return [
'Plain template' => [
'hasfield' => false,
'hasotherfields' => false,
'expected' => true,
],
'Field already present' => [
'hasfield' => true,
'hasotherfields' => false,
'expected' => false,
],
'##otherfields## tag present' => [
'hasfield' => false,
'hasotherfields' => true,
'expected' => false,
],
'Field already present and ##otherfields## tag present' => [
'hasfield' => true,
'hasotherfields' => true,
'expected' => false,
],
];
}
}

View File

@ -97,17 +97,19 @@ class template_test extends \advanced_testcase {
// Generate an entry.
$generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
$fieldrecord = (object)[
'name' => 'myfield',
'type' => 'text',
];
$fieldrecord = (object)['name' => 'myfield', 'type' => 'text'];
$field = $generator->create_field($fieldrecord, $activity);
$otherfieldrecord = (object)['name' => 'otherfield', 'type' => 'text'];
$otherfield = $generator->create_field($otherfieldrecord, $activity);
$this->setUser($user);
$entryid = $generator->create_entry(
$activity,
[$field->field->id => 'Example entry'],
[
$field->field->id => 'Example entry',
$otherfield->field->id => 'Another example',
],
0,
['Cats', 'Dogs'],
['approved' => $approved]
@ -149,6 +151,8 @@ class template_test extends \advanced_testcase {
'{timeadded}' => userdate($entry->timecreated, get_string('strftimedatemonthabbr', 'langconfig')),
'{timemodified}' => userdate($entry->timemodified, get_string('strftimedatemonthabbr', 'langconfig')),
'{fieldid}' => $field->field->id,
'{fieldname}' => $field->field->name,
'{fielddescription}' => $field->field->description,
'{entryid}' => $entry->id,
'{cmid}' => $cm->id,
'{courseid}' => $course->id,
@ -330,11 +334,21 @@ class template_test extends \advanced_testcase {
'expected' => '|Some .*Example entry.* tag|',
'rolename' => 'editingteacher',
],
'Teacher field#id name tag' => [
'Teacher field#id tag' => [
'templatecontent' => 'Some [[myfield#id]] tag',
'expected' => '|Some {fieldid} tag|',
'rolename' => 'editingteacher',
],
'Teacher field#name tag' => [
'templatecontent' => 'Some [[myfield#name]] tag',
'expected' => '|Some {fieldname} tag|',
'rolename' => 'editingteacher',
],
'Teacher field#description tag' => [
'templatecontent' => 'Some [[myfield#description]] tag',
'expected' => '|Some {fielddescription} tag|',
'rolename' => 'editingteacher',
],
'Teacher comments name tag with comments enabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some .*Comments.* tag|',
@ -434,6 +448,16 @@ class template_test extends \advanced_testcase {
'enableratings' => false,
'options' => ['showmore' => true],
],
'Teacher otherfields tag' => [
'templatecontent' => 'Some ##otherfields## tag',
'expected' => '|Some .*{fieldname}.*Example entry.*otherfield.*Another example.* tag|',
'rolename' => 'editingteacher',
],
'Teacher otherfields tag with some field in the template' => [
'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
'expected' => '|Some .*Example entry.* and .*otherfield.*Another example.* tag|',
'rolename' => 'editingteacher',
],
// Student scenarios.
'Student id tag' => [
'templatecontent' => 'Some ##id## tag',
@ -631,6 +655,16 @@ class template_test extends \advanced_testcase {
'expected' => '|Some {fieldid} tag|',
'rolename' => 'student',
],
'Student field#name tag' => [
'templatecontent' => 'Some [[myfield#name]] tag',
'expected' => '|Some {fieldname} tag|',
'rolename' => 'student',
],
'Student field#description tag' => [
'templatecontent' => 'Some [[myfield#description]] tag',
'expected' => '|Some {fielddescription} tag|',
'rolename' => 'student',
],
'Student comments name tag with comments enabled' => [
'templatecontent' => 'Some ##comments## tag',
'expected' => '|Some .*Comments.* tag|',
@ -730,6 +764,16 @@ class template_test extends \advanced_testcase {
'enableratings' => false,
'options' => ['showmore' => true],
],
'Student otherfields tag' => [
'templatecontent' => 'Some ##otherfields## tag',
'expected' => '|Some .*{fieldname}.*Example entry.*otherfield.*Another example.* tag|',
'rolename' => 'student',
],
'Student otherfields tag with some field in the template' => [
'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
'expected' => '|Some .*Example entry.* and .*otherfield.*Another example.* tag|',
'rolename' => 'student',
],
];
}
@ -825,8 +869,11 @@ class template_test extends \advanced_testcase {
$fieldrecord = (object)[
'name' => 'myfield',
'type' => 'text',
'description' => 'This is a field'
];
$field = $generator->create_field($fieldrecord, $activity);
$otherfieldrecord = (object)['name' => 'otherfield', 'type' => 'text'];
$otherfield = $generator->create_field($otherfieldrecord, $activity);
if ($newentry) {
$entryid = null;
@ -834,7 +881,10 @@ class template_test extends \advanced_testcase {
} else {
$entryid = $generator->create_entry(
$activity,
[$field->field->id => 'Example entry'],
[
$field->field->id => 'Example entry',
$otherfield->field->id => 'Another example',
],
0,
['Cats', 'Dogs']
);
@ -842,6 +892,7 @@ class template_test extends \advanced_testcase {
'd' => $activity->id,
'rid' => $entryid,
"field_{$field->field->id}" => "New value",
"field_{$otherfield->field->id}" => "Altered value",
];
}
@ -850,11 +901,17 @@ class template_test extends \advanced_testcase {
// Some cooked variables for the regular expression.
$replace = [
'{fieldid}' => $field->field->id,
'{fieldname}' => $field->field->name,
'{fielddescription}' => $field->field->description,
'{otherid}' => $otherfield->field->id,
];
$processdata = (object)[
'generalnotifications' => ['GENERAL'],
'fieldnotifications' => [$field->field->name => ['FIELD']],
'fieldnotifications' => [
$field->field->name => ['FIELD'],
$otherfield->field->name => ['OTHERFIELD'],
],
];
$parser = new template($manager, $templatecontent);
@ -889,6 +946,22 @@ class template_test extends \advanced_testcase {
'expected' => '|GENERAL.*Some field_{fieldid} tag|',
'newentry' => false,
],
'Teacher editing field#name tag' => [
'templatecontent' => 'Some [[myfield#name]] tag',
'expected' => '|GENERAL.*Some {fieldname} tag|',
'newentry' => false,
],
'Teacher editing field#description tag' => [
'templatecontent' => 'Some [[myfield#description]] tag',
'expected' => '|GENERAL.*Some {fielddescription} tag|',
'newentry' => false,
],
'Teacher editing entry field otherfields tag' => [
'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* '
. 'and .*OTHERFIELD.*field_{otherid}.*input.*Altered value.* tag|',
'newentry' => false,
],
// New entry.
'Teacher new entry tags tag' => [
'templatecontent' => 'Some ##tags## tag',
@ -905,6 +978,22 @@ class template_test extends \advanced_testcase {
'expected' => '|GENERAL.*Some field_{fieldid} tag|',
'newentry' => true,
],
'Teacher new entry field#name tag' => [
'templatecontent' => 'Some [[myfield#name]] tag',
'expected' => '|GENERAL.*Some {fieldname} tag|',
'newentry' => false,
],
'Teacher new entry field#description tag' => [
'templatecontent' => 'Some [[myfield#description]] tag',
'expected' => '|GENERAL.*Some {fielddescription} tag|',
'newentry' => false,
],
'Teacher new entry field otherfields tag' => [
'templatecontent' => 'Some [[myfield]] and ##otherfields## tag',
'expected' => '|GENERAL.*Some .*FIELD.*field_{fieldid}.*input.*New value.* '
. '.* and .*OTHERFIELD.*field_{otherid}.*input.*Altered value.* |',
'newentry' => false,
],
];
}
}

View File

@ -4,6 +4,12 @@ information provided here is intended especially for developers.
== 4.2 ==
* The field base class now has a method validate(). Overwrite it in the field type to provide validation of field type's
parameters in the field add/modify form.
* New tags are added to the current mod_data\templates class: ##otherfields##, [[FIELD#name]],
and [[FIELD#description]].
* The mod_data\template class can provide preprocessor methods to optimize some tags. From now on,
when load_template_tags detects a tag, it will call a "preprocess_tag_TAGNAME" method if it exists.
This preprocessing can be used, for example, to precalculate some content. Currently, this preprocessor
is used to detect which fields needs to be renderer when a ##otherfields## is used.
=== 4.1 ===
* The method data_view is now deprecated. Use $maganer->set_module_viewed instead.