diff --git a/lib/outputcomponents.php b/lib/outputcomponents.php
index 27bb8cafa88..850d4b2bb75 100644
--- a/lib/outputcomponents.php
+++ b/lib/outputcomponents.php
@@ -4569,6 +4569,19 @@ class action_menu implements renderable, templatable {
}
}
+ /**
+ * Add classes to the action menu for an easier styling.
+ *
+ * @param string $class The class to add to attributes.
+ */
+ public function set_additional_classes(string $class = '') {
+ if (!empty($this->attributes['class'])) {
+ $this->attributes['class'] .= " ".$class;
+ } else {
+ $this->attributes['class'] = $class;
+ }
+ }
+
/**
* Export for template.
*
diff --git a/lib/upgrade.txt b/lib/upgrade.txt
index 13d2d7ec979..62fef4b040e 100644
--- a/lib/upgrade.txt
+++ b/lib/upgrade.txt
@@ -12,9 +12,6 @@ Declaration is as follow:
* coursemodinfo cache uses the new `requirelockingbeforewrite` option, and rebuilding the cache now uses the cache lock API, rather
than using the core lock factory directly. This allows the locks to be stored locally if the cache is stored locally, and
avoids the risk of delays and timeouts when multiple nodes need to rebuild the cache locally, but are waiting for a central lock.
-
-=== 4.1 ===
-
* Final deprecation and removal of the class \admin_setting_managelicenses, please use \tool_licensemanager\manager instead.
* Final deprecation and removal of the function license_manager::add(). Please use license_manager::save() instead.
* Final deprecation of the following functions behat_field_manager::get_node_type() and behat_field_manager::get_field()
@@ -60,6 +57,7 @@ Declaration is as follow:
* The function get_module_metadata() has been finally deprecated and can not be used anymore.
* New DML driver method `$DB->sql_order_by_null` for sorting nulls sort nulls first when ascending and last when descending.
* Allow plugins to callback on all pages just prior to the session start.
+* New function set_additional_classes() has been implemented to add additional classes to action_menu.
=== 4.0 ===
diff --git a/mod/data/amd/build/selectpreset.min.js.map b/mod/data/amd/build/selectpreset.min.js.map
index 6ec272a58b0..e7ee516bd6d 100644
--- a/mod/data/amd/build/selectpreset.min.js.map
+++ b/mod/data/amd/build/selectpreset.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"selectpreset.min.js","sources":["../src/selectpreset.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module to control the form responsible for selecting a preset.\n *\n * @module mod_data/selectpreset\n * @copyright 2021 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst selectors = {\n presetRadioButton: 'input[name=\"fullname\"]',\n selectPresetButton: 'input[name=\"selectpreset\"]',\n selectedPresetRadioButton: 'input[name=\"fullname\"]:checked',\n};\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const radioButton = document.querySelectorAll(selectors.presetRadioButton);\n\n // Initialize the \"Use preset\" button properly.\n disableUsePresetButton();\n\n radioButton.forEach((elem) => {\n elem.addEventListener('change', function(event) {\n event.preventDefault();\n // Enable the \"Use preset\" button when any of the radio buttons in the presets list is checked.\n disableUsePresetButton();\n });\n });\n\n};\n\n/**\n * Decide whether to disable or not the \"Use preset\" button.\n * When there is no preset selected, the button should be displayed disabled; otherwise, it will appear enabled as a primary button.\n *\n * @method\n * @private\n */\nconst disableUsePresetButton = () => {\n let selectPresetButton = document.querySelector(selectors.selectPresetButton);\n const selectedRadioButton = document.querySelectorAll(selectors.selectedPresetRadioButton);\n\n if (selectedRadioButton.length > 0) {\n // There is one preset selected, so the button should be enabled.\n selectPresetButton.removeAttribute('disabled');\n selectPresetButton.classList.remove('btn-secondary');\n selectPresetButton.classList.add('btn-primary');\n } else {\n // There is no any preset selected, so the button should be disabled.\n selectPresetButton.setAttribute('disabled', true);\n selectPresetButton.classList.remove('btn-primary');\n selectPresetButton.classList.add('btn-secondary');\n }\n};\n"],"names":["selectors","radioButton","document","querySelectorAll","disableUsePresetButton","forEach","elem","addEventListener","event","preventDefault","selectPresetButton","querySelector","length","removeAttribute","classList","remove","add","setAttribute"],"mappings":";;;;;;;;MAuBMA,4BACiB,yBADjBA,6BAEkB,6BAFlBA,oCAGyB,+CAMX,WACVC,YAAcC,SAASC,iBAAiBH,6BAG9CI,yBAEAH,YAAYI,SAASC,OACjBA,KAAKC,iBAAiB,UAAU,SAASC,OACrCA,MAAMC,iBAENL,sCAaNA,uBAAyB,SACvBM,mBAAqBR,SAASS,cAAcX,8BACpBE,SAASC,iBAAiBH,qCAE9BY,OAAS,GAE7BF,mBAAmBG,gBAAgB,YACnCH,mBAAmBI,UAAUC,OAAO,iBACpCL,mBAAmBI,UAAUE,IAAI,iBAGjCN,mBAAmBO,aAAa,YAAY,GAC5CP,mBAAmBI,UAAUC,OAAO,eACpCL,mBAAmBI,UAAUE,IAAI"}
\ No newline at end of file
+{"version":3,"file":"selectpreset.min.js","sources":["../src/selectpreset.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript module to control the form responsible for selecting a preset.\n *\n * @module mod_data/selectpreset\n * @copyright 2021 Mihail Geshoski \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nconst selectors = {\n presetRadioButton: 'input[name=\"fullname\"]',\n selectPresetButton: 'input[name=\"selectpreset\"]',\n selectedPresetRadioButton: 'input[name=\"fullname\"]:checked',\n};\n\n/**\n * Initialize module.\n */\nexport const init = () => {\n const radioButton = document.querySelectorAll(selectors.presetRadioButton);\n\n // Initialize the \"Use a preset\" button properly.\n disableUsePresetButton();\n\n radioButton.forEach((elem) => {\n elem.addEventListener('change', function(event) {\n event.preventDefault();\n // Enable the \"Use a preset\" button when any of the radio buttons in the presets list is checked.\n disableUsePresetButton();\n });\n });\n\n};\n\n/**\n * Decide whether to disable or not the \"Use a preset\" button.\n * When there is no preset selected, the button should be displayed disabled; otherwise, it will appear enabled as a primary button.\n *\n * @method\n * @private\n */\nconst disableUsePresetButton = () => {\n let selectPresetButton = document.querySelector(selectors.selectPresetButton);\n const selectedRadioButton = document.querySelectorAll(selectors.selectedPresetRadioButton);\n\n if (selectedRadioButton.length > 0) {\n // There is one preset selected, so the button should be enabled.\n selectPresetButton.removeAttribute('disabled');\n selectPresetButton.classList.remove('btn-secondary');\n selectPresetButton.classList.add('btn-primary');\n } else {\n // There is no any preset selected, so the button should be disabled.\n selectPresetButton.setAttribute('disabled', true);\n selectPresetButton.classList.remove('btn-primary');\n selectPresetButton.classList.add('btn-secondary');\n }\n};\n"],"names":["selectors","radioButton","document","querySelectorAll","disableUsePresetButton","forEach","elem","addEventListener","event","preventDefault","selectPresetButton","querySelector","length","removeAttribute","classList","remove","add","setAttribute"],"mappings":";;;;;;;;MAuBMA,4BACiB,yBADjBA,6BAEkB,6BAFlBA,oCAGyB,+CAMX,WACVC,YAAcC,SAASC,iBAAiBH,6BAG9CI,yBAEAH,YAAYI,SAASC,OACjBA,KAAKC,iBAAiB,UAAU,SAASC,OACrCA,MAAMC,iBAENL,sCAaNA,uBAAyB,SACvBM,mBAAqBR,SAASS,cAAcX,8BACpBE,SAASC,iBAAiBH,qCAE9BY,OAAS,GAE7BF,mBAAmBG,gBAAgB,YACnCH,mBAAmBI,UAAUC,OAAO,iBACpCL,mBAAmBI,UAAUE,IAAI,iBAGjCN,mBAAmBO,aAAa,YAAY,GAC5CP,mBAAmBI,UAAUC,OAAO,eACpCL,mBAAmBI,UAAUE,IAAI"}
\ No newline at end of file
diff --git a/mod/data/amd/src/selectpreset.js b/mod/data/amd/src/selectpreset.js
index 1ac23b10959..6fd881c2957 100644
--- a/mod/data/amd/src/selectpreset.js
+++ b/mod/data/amd/src/selectpreset.js
@@ -33,13 +33,13 @@ const selectors = {
export const init = () => {
const radioButton = document.querySelectorAll(selectors.presetRadioButton);
- // Initialize the "Use preset" button properly.
+ // Initialize the "Use a preset" button properly.
disableUsePresetButton();
radioButton.forEach((elem) => {
elem.addEventListener('change', function(event) {
event.preventDefault();
- // Enable the "Use preset" button when any of the radio buttons in the presets list is checked.
+ // Enable the "Use a preset" button when any of the radio buttons in the presets list is checked.
disableUsePresetButton();
});
});
@@ -47,7 +47,7 @@ export const init = () => {
};
/**
- * Decide whether to disable or not the "Use preset" button.
+ * Decide whether to disable or not the "Use a preset" button.
* When there is no preset selected, the button should be displayed disabled; otherwise, it will appear enabled as a primary button.
*
* @method
diff --git a/mod/data/classes/manager.php b/mod/data/classes/manager.php
index 8e9ebac175a..02ded23f091 100644
--- a/mod/data/classes/manager.php
+++ b/mod/data/classes/manager.php
@@ -301,6 +301,19 @@ class manager {
return new template($this, $templatecontent, $options);
}
+ /** Check if the user can manage templates on the current context.
+ *
+ * @param int $userid the user id to check ($USER->id if null).
+ * @return bool if the user can manage templates on current context.
+ */
+ public function can_manage_templates(?int $userid = null): bool {
+ global $USER;
+ if (!$userid) {
+ $userid = $USER->id;
+ }
+ return has_capability('mod/data:managetemplates', $this->context, $userid);
+ }
+
/**
* Update the database templates.
*
diff --git a/mod/data/classes/output/action_bar.php b/mod/data/classes/output/action_bar.php
index e4ca9bbe392..ae89ecaa58a 100644
--- a/mod/data/classes/output/action_bar.php
+++ b/mod/data/classes/output/action_bar.php
@@ -54,8 +54,11 @@ class action_bar {
* @param bool $hasexportpreset Whether the export as preset button element should be rendered.
* @return string The HTML code for the action bar.
*/
- public function get_fields_action_bar(bool $hasfieldselect = false, bool $hassaveaspreset = false,
- bool $hasexportpreset = false): string {
+ public function get_fields_action_bar(
+ bool $hasfieldselect = false,
+ bool $hassaveaspreset = false,
+ bool $hasexportpreset = false
+ ): string {
global $PAGE, $DB;
$createfieldlink = new moodle_url('/mod/data/field.php', ['d' => $this->id]);
@@ -70,19 +73,7 @@ class action_bar {
$fieldselect = null;
if ($hasfieldselect) {
- // Get the list of possible fields (plugins).
- $plugins = \core_component::get_plugin_list('datafield');
- $menufield = [];
-
- foreach ($plugins as $plugin => $fulldir) {
- $menufield[$plugin] = get_string('pluginname', "datafield_{$plugin}");
- }
- asort($menufield);
-
- $fieldselecturl = new moodle_url('/mod/data/field.php', ['d' => $this->id, 'mode' => 'new']);
- $fieldselect = new \single_select($fieldselecturl, 'newtype', $menufield, null, get_string('newfield', 'data'),
- 'fieldform');
- $fieldselect->set_label(get_string('newfield', 'mod_data'), ['class' => 'sr-only']);
+ $fieldselect = $this->get_create_fields();
}
$saveaspresetbutton = null;
@@ -105,12 +96,43 @@ class action_bar {
}
}
$renderer = $PAGE->get_renderer('mod_data');
- $fieldsactionbar = new fields_action_bar($this->id, $urlselect, $fieldselect, $saveaspresetbutton,
- $exportpresetbutton);
+ $fieldsactionbar = new fields_action_bar($this->id, $urlselect, null, $saveaspresetbutton,
+ $exportpresetbutton, $fieldselect);
return $renderer->render_fields_action_bar($fieldsactionbar);
}
+ /**
+ * Generate the output for the create a new field action menu.
+ *
+ * @return \action_menu Action menu to create a new field
+ */
+ public function get_create_fields(): \action_menu {
+ // Get the list of possible fields (plugins).
+ $plugins = \core_component::get_plugin_list('datafield');
+ $menufield = [];
+ foreach ($plugins as $plugin => $fulldir) {
+ $menufield[$plugin] = get_string('pluginname', "datafield_{$plugin}");
+ }
+ asort($menufield);
+
+ $fieldselect = new \action_menu();
+ $fieldselect->set_menu_trigger(get_string('newfield', 'mod_data'), 'btn btn-secondary');
+ $fieldselectparams = ['d' => $this->id, 'mode' => 'new'];
+ foreach ($menufield as $fieldtype => $fieldname) {
+ $fieldselectparams['newtype'] = $fieldtype;
+ $fieldselect->add(new \action_menu_link(
+ new \moodle_url('/mod/data/field.php', $fieldselectparams),
+ new \pix_icon('field/' . $fieldtype, $fieldname, 'data'),
+ $fieldname,
+ false
+ ));
+ }
+ $fieldselect->set_additional_classes('singlebutton');
+
+ return $fieldselect;
+ }
+
/**
* Generate the output for the action selector in the view page.
*
diff --git a/mod/data/classes/output/fields_action_bar.php b/mod/data/classes/output/fields_action_bar.php
index 83e3455e7a5..0ed542f03e1 100644
--- a/mod/data/classes/output/fields_action_bar.php
+++ b/mod/data/classes/output/fields_action_bar.php
@@ -48,12 +48,19 @@ class fields_action_bar implements templatable, renderable {
*
* @param int $id The database module id
* @param \url_select $urlselect The URL selector object
- * @param \single_select|null $fieldselect The field selector object or null
+ * @param null $unused This parameter has been deprecated since 4.0 and should not be used anymore.
* @param \single_button|null $saveaspresetbutton The save as preset single button object or null
* @param \single_button|null $exportpresetbutton The export preset single button object or null
+ * @param \action_menu|null $fieldselect The field selector object or null
*/
- public function __construct(int $id, \url_select $urlselect, ?\single_select $fieldselect = null,
- ?\single_button $saveaspresetbutton = null, ?\single_button $exportpresetbutton = null) {
+ public function __construct(int $id, \url_select $urlselect, $unused = null,
+ ?\single_button $saveaspresetbutton = null, ?\single_button $exportpresetbutton = null,
+ ?\action_menu $fieldselect = null) {
+
+ if ($unused !== null) {
+ debugging('Deprecated argument passed to fields_action_bar constructor', DEBUG_DEVELOPER);
+ }
+
$this->id = $id;
$this->urlselect = $urlselect;
$this->fieldselect = $fieldselect;
diff --git a/mod/data/classes/output/zero_state_action_bar.php b/mod/data/classes/output/zero_state_action_bar.php
index 64030ac9e8d..d92ea1a4baa 100644
--- a/mod/data/classes/output/zero_state_action_bar.php
+++ b/mod/data/classes/output/zero_state_action_bar.php
@@ -52,7 +52,7 @@ class zero_state_action_bar implements templatable, renderable {
global $PAGE;
$data = [];
- if (has_capability('mod/data:managetemplates', $PAGE->context)) {
+ if ($this->manager->can_manage_templates()) {
$instance = $this->manager->get_instance();
$params = ['d' => $instance->id, 'backto' => $PAGE->url->out(false)];
@@ -61,9 +61,8 @@ class zero_state_action_bar implements templatable, renderable {
get_string('usepreset', 'mod_data'), 'get', true);
$data['usepresetbutton'] = $usepresetbutton->export_for_template($output);
- $createfieldlink = new moodle_url('/mod/data/field.php', $params);
- $createfieldbutton = new \single_button($createfieldlink,
- get_string('newfield', 'mod_data'), 'get', false);
+ $actionbar = new \mod_data\output\action_bar($instance->id, $PAGE->url);
+ $createfieldbutton = $actionbar->get_create_fields();
$data['createfieldbutton'] = $createfieldbutton->export_for_template($output);
$params['action'] = 'import';
diff --git a/mod/data/edit.php b/mod/data/edit.php
index 12b462732b8..6587516ada5 100644
--- a/mod/data/edit.php
+++ b/mod/data/edit.php
@@ -74,7 +74,7 @@ if (isguestuser()) {
}
/// Can't use this if there are no fields
-if (has_capability('mod/data:managetemplates', $context)) {
+if ($manager->can_manage_templates()) {
if (!$manager->has_fields()) {
redirect($CFG->wwwroot.'/mod/data/field.php?d='.$data->id); // Redirect to field entry.
}
diff --git a/mod/data/field.php b/mod/data/field.php
index 4eb2e2c0255..1c89d2a3f4b 100644
--- a/mod/data/field.php
+++ b/mod/data/field.php
@@ -333,75 +333,79 @@ if (($mode == 'new') && (!empty($newtype))) { // Adding a new field.
$field->display_edit_field();
} else { /// Display the main listing of all fields
+ $hasfields = $manager->has_fields();
+
+ // Check if it is an empty database with no fields.
+ if (!$hasfields) {
+ $PAGE->set_title($data->name);
+ echo $OUTPUT->header();
+ echo $renderer->render_fields_zero_state($manager);
+ echo $OUTPUT->footer();
+ // Don't check the rest of the options. There is no field, there is nothing else to work with.
+ exit;
+ }
$fieldactionbar = $actionbar->get_fields_action_bar(true, true, true);
data_print_header($course, $cm, $data, 'fields', $fieldactionbar);
echo $OUTPUT->heading(get_string('managefields', 'data'), 2, 'mb-4');
- if (!$DB->record_exists('data_fields', array('dataid'=>$data->id))) {
- echo $OUTPUT->notification(get_string('nofieldindatabase','data')); // nothing in database
- echo $OUTPUT->notification(get_string('pleaseaddsome','data', 'preset.php?id='.$cm->id)); // link to presets
+ $table = new html_table();
+ $table->head = [
+ get_string('fieldname', 'data'),
+ get_string('type', 'data'),
+ get_string('required', 'data'),
+ get_string('fielddescription', 'data'),
+ get_string('action', 'data'),
+ ];
+ $table->align = ['left', 'left', 'left', 'left'];
+ $table->wrap = [false,false,false,false];
- } else { //else print quiz style list of fields
+ $fieldrecords = $manager->get_field_records();
+ $missingfieldtypes = [];
+ foreach ($fieldrecords as $fieldrecord) {
- $table = new html_table();
- $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', 'left');
- $table->wrap = array(false,false,false,false);
+ $field = data_get_field($fieldrecord, $data);
- if ($fff = $DB->get_records('data_fields', array('dataid'=>$data->id),'id')){
- $missingfieldtypes = [];
- foreach ($fff as $ff) {
+ $baseurl = new moodle_url('/mod/data/field.php', array(
+ 'd' => $data->id,
+ 'fid' => $field->field->id,
+ 'sesskey' => sesskey(),
+ ));
- $field = data_get_field($ff, $data);
+ $displayurl = new moodle_url($baseurl, array(
+ 'mode' => 'display',
+ ));
- $baseurl = new moodle_url('/mod/data/field.php', array(
- 'd' => $data->id,
- 'fid' => $field->field->id,
- 'sesskey' => sesskey(),
- ));
+ $deleteurl = new moodle_url($baseurl, array(
+ 'mode' => 'delete',
+ ));
- $displayurl = new moodle_url($baseurl, array(
- 'mode' => 'display',
- ));
-
- $deleteurl = new moodle_url($baseurl, array(
- 'mode' => 'delete',
- ));
-
- // It display a notification when the field type does not exist.
- $deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
- $editlink = html_writer::link($displayurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
- if ($field->type === 'unknown') {
- $missingfieldtypes[] = $field->field->name;
- $fieldnamedata = $field->field->name;
- $fieltypedata = $field->field->type;
- $fieldlinkdata = $deletelink;
- } else {
- $fieldnamedata = html_writer::link($displayurl, $field->field->name);
- $fieltypedata = $field->image() . ' ' . $field->name();
- $fieldlinkdata = $editlink . ' ' . $deletelink;
- }
-
- $table->data[] = [
- $fieldnamedata,
- $fieltypedata,
- $field->field->required ? get_string('yes') : get_string('no'),
- shorten_text($field->field->description, 30),
- $fieldlinkdata
- ];
- }
- if (!empty($missingfieldtypes)) {
- echo $OUTPUT->notification(get_string('missingfieldtypes', 'data') . html_writer::alist($missingfieldtypes));
- }
+ // It display a notification when the field type does not exist.
+ $deletelink = html_writer::link($deleteurl, $OUTPUT->pix_icon('t/delete', get_string('delete')));
+ $editlink = html_writer::link($displayurl, $OUTPUT->pix_icon('t/edit', get_string('edit')));
+ if ($field->type === 'unknown') {
+ $missingfieldtypes[] = $field->field->name;
+ $fieldnamedata = $field->field->name;
+ $fieltypedata = $field->field->type;
+ $fieldlinkdata = $deletelink;
+ } else {
+ $fieldnamedata = html_writer::link($displayurl, $field->field->name);
+ $fieltypedata = $field->image() . ' ' . $field->name();
+ $fieldlinkdata = $editlink . ' ' . $deletelink;
+ }
+
+ $table->data[] = [
+ $fieldnamedata,
+ $fieltypedata,
+ $field->field->required ? get_string('yes') : get_string('no'),
+ shorten_text($field->field->description, 30),
+ $fieldlinkdata
+ ];
+
+ if (!empty($missingfieldtypes)) {
+ echo $OUTPUT->notification(get_string('missingfieldtypes', 'data') . html_writer::alist($missingfieldtypes));
}
- echo html_writer::table($table);
}
+ echo html_writer::table($table);
echo '
{{/exportpreset}}
+ {{#fieldselect}}
+ {{>core/action_menu}}
+ {{/fieldselect}}
diff --git a/mod/data/templates/zero_state.mustache b/mod/data/templates/zero_state.mustache
index 2a5274e45b2..8236aea57b6 100644
--- a/mod/data/templates/zero_state.mustache
+++ b/mod/data/templates/zero_state.mustache
@@ -19,7 +19,7 @@
Context variables required for this template:
* noitemsimgurl - The image url.
* importpresetbutton stdClass - Import preset single button to be rendered
- * createfieldbutton stdClass - Create a new field single button to be rendered
+ * createfieldbutton stdClass - Create a field action menu to be rendered
* usepresetbutton stdClass - Use a preset single button to be rendered
Example context (json):
@@ -77,15 +77,17 @@
style="height: 70px; width: 70px;"
>
{{{ title }}}
-
{{{ intro }}}
+ {{#intro}}
+
{{{ intro }}}
+ {{/intro}}
-
+
+ {{#createfieldbutton}}
+ {{>core/action_menu}}
+ {{/createfieldbutton}}
{{#importpresetbutton}}
{{>core/single_button}}
{{/importpresetbutton}}
- {{#createfieldbutton}}
- {{>core/single_button}}
- {{/createfieldbutton}}
{{#usepresetbutton}}
{{>core/single_button}}
{{/usepresetbutton}}
diff --git a/mod/data/tests/behat/behat_mod_data.php b/mod/data/tests/behat/behat_mod_data.php
index 98b65434223..fa0ee3eeaab 100644
--- a/mod/data/tests/behat/behat_mod_data.php
+++ b/mod/data/tests/behat/behat_mod_data.php
@@ -53,7 +53,10 @@ class behat_mod_data extends behat_base {
$fieldsstr = get_string('fields', 'mod_data');
$this->execute("behat_navigation::i_navigate_to_in_current_page_administration", $fieldsstr);
- $this->execute('behat_forms::i_set_the_field_to', array('newtype', $this->escape($fieldtype)));
+ $this->execute('behat_general::i_click_on', [get_string('newfield', 'mod_data'), "button"]);
+ $this->execute('behat_general::i_click_on_in_the',
+ [$this->escape($fieldtype), "link", "#action_bar", "css_element"]
+ );
if (!$this->running_javascript()) {
$this->execute('behat_general::i_click_on_in_the',
diff --git a/mod/data/tests/behat/data_activity_completion.feature b/mod/data/tests/behat/data_activity_completion.feature
index 09c6a7efa91..199ea9af2c1 100644
--- a/mod/data/tests/behat/data_activity_completion.feature
+++ b/mod/data/tests/behat/data_activity_completion.feature
@@ -1,4 +1,4 @@
-@mod @mod_data @core_completion
+@mod @mod_data @core_completion @javascript
Feature: View activity completion in the database activity
In order to have visibility of database completion requirements
As a student
@@ -77,7 +77,6 @@ Feature: View activity completion in the database activity
And I am on the "Music history" "data activity" page logged in as teacher1
And I select "Single view" from the "jump" singleselect
And I set the field "rating" to "3"
- And I press "Rate"
And I log out
When I am on the "Music history" "data activity" page logged in as student1
diff --git a/mod/data/tests/behat/data_activity_completion_pass_grade.feature b/mod/data/tests/behat/data_activity_completion_pass_grade.feature
index 17994603d2b..a624cfb62f5 100644
--- a/mod/data/tests/behat/data_activity_completion_pass_grade.feature
+++ b/mod/data/tests/behat/data_activity_completion_pass_grade.feature
@@ -52,6 +52,7 @@ Feature: Completion pass grade
| Field name | Instrument types |
And I log out
+ @javascript
Scenario: View automatic completion items as a teacher
Given I am on the "Music history" "data activity" page logged in as teacher1
# We add an entry to let the user change to a different view.
diff --git a/mod/data/tests/behat/data_presets.feature b/mod/data/tests/behat/data_presets.feature
index e18f24b64cb..aea0d15eee1 100644
--- a/mod/data/tests/behat/data_presets.feature
+++ b/mod/data/tests/behat/data_presets.feature
@@ -63,10 +63,10 @@ Feature: Users can view and manage data presets
And I should see "Delete"
# Teachers can't delete the presets they haven't created.
And I should not see "Actions" in the "Saved preset 1" "table_row"
- # The "Use preset" button should be enabled only when a preset is selected.
- And the "Use preset" "button" should be disabled
+ # The "Use a preset" button should be enabled only when a preset is selected.
+ And the "Use a preset" "button" should be disabled
And I click on "fullname" "radio" in the "Image gallery" "table_row"
- And the "Use preset" "button" should be enabled
+ And the "Use a preset" "button" should be enabled
@javascript
Scenario: Only users with the viewalluserpresets capability can see presets created by other users
@@ -286,7 +286,7 @@ Feature: Users can view and manage data presets
And I should see "My funny description goes here"
And I should see "Test field name"
And I should see "This is a short text"
- Then "Use preset" "button" should exist
+ Then "Use a preset" "button" should exist
@javascript
Scenario: Teachers can export any saved preset
diff --git a/mod/data/tests/behat/preview_preset.feature b/mod/data/tests/behat/preview_preset.feature
index 489d4973099..0325bb65acf 100644
--- a/mod/data/tests/behat/preview_preset.feature
+++ b/mod/data/tests/behat/preview_preset.feature
@@ -138,8 +138,9 @@ Feature: Users can preview presets
Scenario: Apply plugin preset from preview in database
Given I follow "Presets"
And I click on "Image gallery" "link"
- When I click on "Use preset" "button"
+ When I click on "Use a preset" "button"
Then I should see "image"
+ And I should see "image"
And I should see "title"
@javascript @_file_upload
@@ -155,5 +156,5 @@ Feature: Users can preview presets
And I click on "Save" "button" in the "Save all fields and templates as preset" "dialogue"
When I follow "Presets"
And I click on "Saved preset by teacher1" "link"
- And I click on "Use preset" "button"
+ And I click on "Use a preset" "button"
Then I should see "My URL field"
diff --git a/mod/data/tests/behat/zero_state.feature b/mod/data/tests/behat/zero_state.feature
index 10380dd2029..9bfdac7f624 100644
--- a/mod/data/tests/behat/zero_state.feature
+++ b/mod/data/tests/behat/zero_state.feature
@@ -1,4 +1,4 @@
-@mod @mod_data
+@mod @mod_data @javascript
Feature: Zero state page (no fields created)
Background:
@@ -15,17 +15,45 @@ Feature: Zero state page (no fields created)
| activity | name | intro | course | idnumber |
| data | Test database name | n | C1 | data1 |
- @javascript
- Scenario: Teachers see buttons to manage database when there is no field created
+ Scenario: Teachers see buttons to manage database when there is no field created on view page
Given I am on the "Test database name" "data activity" page logged in as "teacher1"
And "Import a preset" "button" should exist
When I click on "Import a preset" "button"
Then I should see "Import from zip file"
And I am on the "Test database name" "data activity" page
- And "Create a new field" "button" should exist
- And I click on "Create a new field" "button"
- And I should see "Manage fields"
+ And "Create a field" "button" should exist
+ And I click on "Create a field" "button"
+ And I click on "Short text" "link"
+ And I should see "Create a field"
And I am on the "Test database name" "data activity" page
- And "Use preset" "button" should exist
- And I click on "Use preset" "button"
+ And "Use a preset" "button" should exist
+ And I click on "Use a preset" "button"
And I should see "Presets"
+
+ Scenario: Teachers see buttons to manage database when there is no field created on templates page
+ Given I am on the "Test database name" "data activity" page logged in as "teacher1"
+ And "Import a preset" "button" should exist
+ When I click on "Import a preset" "button"
+ Then I should see "Import from zip file"
+ And I am on the "Test database name" "data activity" page
+ And I click on "Templates" "link"
+ And "Create a field" "button" should exist
+ And I click on "Create a field" "button"
+ And I click on "Short text" "link"
+ And I should see "Create a field"
+ And I am on the "Test database name" "data activity" page
+ And I click on "Templates" "link"
+ And "Use a preset" "button" should exist
+ And I click on "Use a preset" "button"
+ And I should see "Presets"
+
+ Scenario: Teachers see buttons to manage database when there is no field created on fields page
+ Given I am on the "Test database name" "data activity" page logged in as "teacher1"
+ And I click on "Fields" "link"
+ And "Import a preset" "button" should not exist
+ And "Use a preset" "button" should not exist
+ And "Create a field" "button" should exist
+ Then I should see "No fields yet"
+ And I click on "Create a field" "button"
+ And I click on "Short text" "link"
+ And I should see "Create a field"
diff --git a/mod/data/upgrade.txt b/mod/data/upgrade.txt
index fc941e61835..0dcb9efb11a 100644
--- a/mod/data/upgrade.txt
+++ b/mod/data/upgrade.txt
@@ -22,6 +22,8 @@ information provided here is intended especially for developers.
- data_preset_existing_importer
- data_preset_upload_importer
* import_setting_mappings() function has been deprecated. Use importing_preset() instead.
+* $fieldselect single_select type parameter has been deprecated for fields_action_bar class constructor, and a new action_menu
+ type parameter has been added.
=== 3.7 ===
* External functions get_entries, get_entry and search_entries now return an additional field "tags" containing the entry tags.
diff --git a/mod/data/view.php b/mod/data/view.php
index 13ec9f551a1..e28e0208838 100644
--- a/mod/data/view.php
+++ b/mod/data/view.php
@@ -242,7 +242,7 @@ echo $OUTPUT->header();
if (!$manager->has_fields()) {
// It's a brand-new database. There are no fields.
$renderer = $manager->get_renderer();
- echo $renderer->render_zero_state($manager);
+ echo $renderer->render_database_zero_state($manager);
echo $OUTPUT->footer();
// Don't check the rest of the options. There is no field, there is nothing else to work with.
exit;
diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss
index 0a900e37334..dc562875387 100644
--- a/theme/boost/scss/moodle/core.scss
+++ b/theme/boost/scss/moodle/core.scss
@@ -18,7 +18,6 @@ $thin-scroll-bg-hover: $gray-700 !default;
$font-size-xs: ($font-size-base * .75) !default;
#region-main {
- overflow-x: auto;
overflow-y: visible;
background-color: $body-bg;
}
diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css
index ee5593a925c..f89e9a55f31 100644
--- a/theme/boost/style/moodle.css
+++ b/theme/boost/style/moodle.css
@@ -9860,7 +9860,6 @@ a.text-dark:hover, a.text-dark:focus {
*/
/* core.less */
#region-main {
- overflow-x: auto;
overflow-y: visible;
background-color: #fff; }
diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css
index 17ceff5b1f8..f71d75697ef 100644
--- a/theme/classic/style/moodle.css
+++ b/theme/classic/style/moodle.css
@@ -9860,7 +9860,6 @@ a.text-dark:hover, a.text-dark:focus {
*/
/* core.less */
#region-main {
- overflow-x: auto;
overflow-y: visible;
background-color: #fff; }