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/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', - )); + // 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; + } - $deleteurl = new moodle_url($baseurl, array( - 'mode' => 'delete', - )); + $table->data[] = [ + $fieldnamedata, + $fieltypedata, + $field->field->required ? get_string('yes') : get_string('no'), + shorten_text($field->field->description, 30), + $fieldlinkdata + ]; - // 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)); - } + 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 '
{{{ intro }}}
+ {{#intro}} +{{{ intro }}}
+ {{/intro}} -