diff --git a/mod/data/classes/manager.php b/mod/data/classes/manager.php index 02ded23f091..ab866db0049 100644 --- a/mod/data/classes/manager.php +++ b/mod/data/classes/manager.php @@ -314,6 +314,25 @@ class manager { return has_capability('mod/data:managetemplates', $this->context, $userid); } + /** Check if the user can export entries on the current context. + * + * @param int $userid the user id to check ($USER->id if null). + * @return bool if the user can export entries on current context. + */ + public function can_export_entries(?int $userid = null): bool { + global $USER, $DB; + + if (!$userid) { + $userid = $USER->id; + } + + // Exportallentries and exportentry are basically the same capability. + return has_capability('mod/data:exportallentries', $this->context) || + has_capability('mod/data:exportentry', $this->context) || + (has_capability('mod/data:exportownentry', $this->context) && + $DB->record_exists('data_records', ['userid' => $userid, 'dataid' => $this->instance->id])); + } + /** * Update the database templates. * diff --git a/mod/data/classes/output/action_bar.php b/mod/data/classes/output/action_bar.php index 429b3f2b7c9..3ffb943688d 100644 --- a/mod/data/classes/output/action_bar.php +++ b/mod/data/classes/output/action_bar.php @@ -17,6 +17,7 @@ namespace mod_data\output; use mod_data\manager; +use mod_data\preset; use moodle_url; use url_select; @@ -55,57 +56,28 @@ class action_bar { * Generate the output for the action bar in the field page. * * @param bool $hasfieldselect Whether the field selector element should be rendered. - * @param bool $hassaveaspreset Whether the save as preset button element should be rendered. - * @param bool $hasexportpreset Whether the export as preset button element should be rendered. + * @param null $unused1 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param null $unused2 This parameter has been deprecated since 4.1 and should not be used anymore. * @return string The HTML code for the action bar. */ public function get_fields_action_bar( bool $hasfieldselect = false, - bool $hassaveaspreset = false, - bool $hasexportpreset = false + ?bool $unused1 = null, + ?bool $unused2 = null ): string { - global $PAGE, $DB; + global $PAGE; - $createfieldlink = new moodle_url('/mod/data/field.php', ['id' => $this->cmid]); - $presetslink = new moodle_url('/mod/data/preset.php', ['id' => $this->cmid]); - - $menu = [ - $createfieldlink->out(false) => get_string('managefields', 'mod_data'), - $presetslink->out(false) => get_string('usestandard', 'mod_data'), - ]; - - $selected = $createfieldlink->out(false); - - $urlselect = new url_select($menu, $selected, null, 'fieldactionselect'); - $urlselect->set_label(get_string('fieldsnavigation', 'mod_data'), ['class' => 'sr-only']); + if ($unused1 !== null || $unused2 !== null) { + debugging('Deprecated argument passed to get_fields_action_bar method', DEBUG_DEVELOPER); + } $fieldselect = null; if ($hasfieldselect) { $fieldselect = $this->get_create_fields(); } - $saveaspresetbutton = null; - $exportpresetbutton = null; - $hasfields = $DB->record_exists('data_fields', ['dataid' => $this->id]); - - if ($hasfields) { - if ($hassaveaspreset) { - $saveaspresetlink = new moodle_url('/mod/data/preset.php', - ['d' => $this->id, 'action' => 'export']); - $saveaspresetbutton = new \single_button($saveaspresetlink, - get_string('saveaspreset', 'mod_data'), 'post', false); - } - - if ($hasexportpreset) { - $exportpresetlink = new moodle_url('/mod/data/preset.php', - ['d' => $this->id, 'action' => 'export']); - $exportpresetbutton = new \single_button($exportpresetlink, - get_string('exportpreset', 'mod_data'), 'get', false); - } - } $renderer = $PAGE->get_renderer('mod_data'); - $fieldsactionbar = new fields_action_bar($this->id, $urlselect, null, $saveaspresetbutton, - $exportpresetbutton, $fieldselect); + $fieldsactionbar = new fields_action_bar($this->id, null, null, null, null, $fieldselect); return $renderer->render_fields_action_bar($fieldsactionbar); } @@ -130,7 +102,7 @@ class action_bar { foreach ($menufield as $fieldtype => $fieldname) { $fieldselectparams['newtype'] = $fieldtype; $fieldselect->add(new \action_menu_link( - new \moodle_url('/mod/data/field.php', $fieldselectparams), + new moodle_url('/mod/data/field.php', $fieldselectparams), new \pix_icon('field/' . $fieldtype, $fieldname, 'data'), $fieldname, false @@ -145,9 +117,10 @@ class action_bar { * Generate the output for the action selector in the view page. * * @param bool $hasentries Whether entries exist. + * @param string $mode The current view mode (list, view...). * @return string The HTML code for the action selector. */ - public function get_view_action_bar(bool $hasentries): string { + public function get_view_action_bar(bool $hasentries, string $mode): string { global $PAGE; $viewlistlink = new moodle_url('/mod/data/view.php', ['d' => $this->id]); @@ -167,7 +140,7 @@ class action_bar { $urlselect = new url_select($menu, $activeurl->out(false), null, 'viewactionselect'); $urlselect->set_label(get_string('viewnavigation', 'mod_data'), ['class' => 'sr-only']); $renderer = $PAGE->get_renderer('mod_data'); - $viewactionbar = new view_action_bar($this->id, $urlselect, $hasentries); + $viewactionbar = new view_action_bar($this->id, $urlselect, $hasentries, $mode); return $renderer->render_view_action_bar($viewactionbar); } @@ -178,7 +151,7 @@ class action_bar { * @return string The HTML code for the action selector. */ public function get_templates_action_bar(): string { - global $PAGE, $DB; + global $PAGE; $listtemplatelink = new moodle_url('/mod/data/templates.php', ['d' => $this->id, 'mode' => 'listtemplate']); @@ -192,38 +165,21 @@ class action_bar { $jstemplatelink = new moodle_url('/mod/data/templates.php', ['d' => $this->id, 'mode' => 'jstemplate']); $menu = [ - $listtemplatelink->out(false) => get_string('listtemplate', 'mod_data'), - $singletemplatelink->out(false) => get_string('singletemplate', 'mod_data'), - $advancedsearchtemplatelink->out(false) => get_string('asearchtemplate', 'mod_data'), $addtemplatelink->out(false) => get_string('addtemplate', 'mod_data'), - $rsstemplatelink->out(false) => get_string('rsstemplate', 'mod_data'), + $singletemplatelink->out(false) => get_string('singletemplate', 'mod_data'), + $listtemplatelink->out(false) => get_string('listtemplate', 'mod_data'), + $advancedsearchtemplatelink->out(false) => get_string('asearchtemplate', 'mod_data'), $csstemplatelink->out(false) => get_string('csstemplate', 'mod_data'), $jstemplatelink->out(false) => get_string('jstemplate', 'mod_data'), + $rsstemplatelink->out(false) => get_string('rsstemplate', 'mod_data'), ]; - $urlselect = new url_select($menu, $this->currenturl->out(false), null, 'templatesactionselect'); - $urlselect->set_label(get_string('templatesnavigation', 'mod_data'), ['class' => 'sr-only']); - - $hasfields = $DB->record_exists('data_fields', ['dataid' => $this->id]); - - $saveaspresetbutton = null; - $exportpresetbutton = null; - - if ($hasfields) { - $saveaspresetlink = new moodle_url('/mod/data/preset.php', - ['d' => $this->id, 'action' => 'export']); - $saveaspresetbutton = new \single_button($saveaspresetlink, - get_string('saveaspreset', 'mod_data'), 'post', false); - - $exportpresetlink = new moodle_url('/mod/data/preset.php', - ['d' => $this->id, 'action' => 'export', 'sesskey' => sesskey()]); - $exportpresetbutton = new \single_button($exportpresetlink, - get_string('exportpreset', 'mod_data'), 'get', false); - } + $selectmenu = new \core\output\select_menu('presetsactions', $menu, $this->currenturl->out(false)); + $selectmenu->set_label(get_string('templatesnavigation', 'mod_data'), ['class' => 'sr-only']); $renderer = $PAGE->get_renderer('mod_data'); - $templatesactionbar = new templates_action_bar($this->id, $urlselect, $saveaspresetbutton, - $exportpresetbutton); + $presetsactions = $this->get_presets_actions_select(false); + $templatesactionbar = new templates_action_bar($this->id, $selectmenu, null, null, $presetsactions); return $renderer->render_templates_action_bar($templatesactionbar); } @@ -237,10 +193,8 @@ class action_bar { global $PAGE; $renderer = $PAGE->get_renderer('mod_data'); - if (!has_capability('mod/data:managetemplates', \context_module::instance($this->cmid))) { - return ''; - } - $presetsactionbar = new presets_action_bar($this->cmid); + $presetsactionbar = new presets_action_bar($this->cmid, $this->get_presets_actions_select(true)); + return $renderer->render_presets_action_bar($presetsactionbar); } @@ -277,7 +231,7 @@ class action_bar { $urlselect->set_label(get_string('templatesnavigation', manager::PLUGINNAME), ['class' => 'sr-only']); $data = [ - 'title' => get_string('preview', manager::PLUGINNAME), + 'title' => get_string('preview', manager::PLUGINNAME, preset::get_name_from_plugin($fullname)), 'hasback' => true, 'backtitle' => get_string('back'), 'backurl' => new moodle_url('/mod/data/preset.php', ['id' => $cm->id]), @@ -285,4 +239,59 @@ class action_bar { ]; return $renderer->render_from_template('mod_data/action_bar', $data); } + + /** + * Helper method to get the selector for the presets action. + * + * @param bool $hasimport Whether the Import buttons must be included or not. + * @return \action_menu|null The selector object used to display the presets actions. Null when the import button is not + * displayed and the database hasn't any fields. + */ + protected function get_presets_actions_select(bool $hasimport = false): ?\action_menu { + global $DB; + + $hasfields = $DB->record_exists('data_fields', ['dataid' => $this->id]); + + // Early return if the database has no fields and the import action won't be displayed. + if (!$hasfields && !$hasimport) { + return null; + } + + $actionsselect = new \action_menu(); + $actionsselect->set_menu_trigger(get_string('actions'), 'btn btn-secondary'); + + if ($hasimport) { + // Import. + $actionsselectparams = ['id' => $this->cmid, 'action' => 'import']; + $actionsselect->add(new \action_menu_link( + new moodle_url('/mod/data/preset.php', $actionsselectparams), + null, + get_string('importpreset', 'mod_data'), + false, + ['data-action' => 'importpresets', 'data-dataid' => $this->cmid] + )); + } + + // If the database has no fields, export and save as preset options shouldn't be displayed. + if ($hasfields) { + // Export. + $actionsselectparams = ['id' => $this->cmid, 'action' => 'export']; + $actionsselect->add(new \action_menu_link( + new moodle_url('/mod/data/preset.php', $actionsselectparams), + null, + get_string('exportpreset', 'mod_data'), + false + )); + // Save as preset. + $actionsselect->add(new \action_menu_link( + new moodle_url('/mod/data/preset.php', $actionsselectparams), + null, + get_string('saveaspreset', 'mod_data'), + false, + ['data-action' => 'saveaspreset', 'data-dataid' => $this->id] + )); + } + + return $actionsselect; + } } diff --git a/mod/data/classes/output/fields_action_bar.php b/mod/data/classes/output/fields_action_bar.php index 0ed542f03e1..31634d52484 100644 --- a/mod/data/classes/output/fields_action_bar.php +++ b/mod/data/classes/output/fields_action_bar.php @@ -31,41 +31,29 @@ class fields_action_bar implements templatable, renderable { /** @var int $id The database module id. */ private $id; - /** @var \url_select $urlselect The URL selector object. */ - private $urlselect; - - /** @var \single_select|null $fieldselect The field selector object or null. */ + /** @var \action_menu|null $fieldselect The field selector object or null. */ private $fieldselect; - /** @var \single_button|null $saveaspresetbutton The save as preset single button object or null. */ - private $saveaspresetbutton; - - /** @var \single_button|null $exportpresetbutton The export preset single button object or null. */ - private $exportpresetbutton; - /** * The class constructor. * * @param int $id The database module id - * @param \url_select $urlselect The URL selector object - * @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 null $unused1 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param null $unused2 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param null $unused3 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param null $unused4 This parameter has been deprecated since 4.1 and should not be used anymore. * @param \action_menu|null $fieldselect The field selector object or null */ - public function __construct(int $id, \url_select $urlselect, $unused = null, - ?\single_button $saveaspresetbutton = null, ?\single_button $exportpresetbutton = null, + public function __construct(int $id, $unused1 = null, $unused2 = null, + $unused3 = null, $unused4 = null, ?\action_menu $fieldselect = null) { - if ($unused !== null) { + if ($unused1 !== null || $unused2 !== null || $unused3 !== null || $unused4 !== null) { debugging('Deprecated argument passed to fields_action_bar constructor', DEBUG_DEVELOPER); } $this->id = $id; - $this->urlselect = $urlselect; $this->fieldselect = $fieldselect; - $this->saveaspresetbutton = $saveaspresetbutton; - $this->exportpresetbutton = $exportpresetbutton; } /** @@ -78,19 +66,12 @@ class fields_action_bar implements templatable, renderable { $data = [ 'd' => $this->id, - 'urlselect' => $this->urlselect->export_for_template($output), ]; if ($this->fieldselect) { $data['fieldselect'] = $this->fieldselect->export_for_template($output); } - $data['saveaspreset'] = $this->saveaspresetbutton; - - if ($this->exportpresetbutton) { - $data['exportpreset'] = $this->exportpresetbutton->export_for_template($output); - } - return $data; } } diff --git a/mod/data/classes/output/presets.php b/mod/data/classes/output/presets.php index 87dedc5f236..d001fe82687 100644 --- a/mod/data/classes/output/presets.php +++ b/mod/data/classes/output/presets.php @@ -100,7 +100,7 @@ class presets implements templatable, renderable { } $actions = $this->get_preset_action_menu($output, $preset, $userid); - $fullname = "{$userid}/{$preset->shortname}"; + $fullname = $preset->get_fullname(); $id = $this->manager->get_instance()->id; $previewurl = new moodle_url( '/mod/data/preset.php', diff --git a/mod/data/classes/output/presets_action_bar.php b/mod/data/classes/output/presets_action_bar.php index 36d335a49b5..15ab0d40c01 100644 --- a/mod/data/classes/output/presets_action_bar.php +++ b/mod/data/classes/output/presets_action_bar.php @@ -16,7 +16,6 @@ namespace mod_data\output; -use moodle_url; use templatable; use renderable; @@ -32,13 +31,18 @@ class presets_action_bar implements templatable, renderable { /** @var int $id The database module id. */ private $cmid; + /** @var \action_menu $actionsselect The presets actions selector object. */ + private $actionsselect; + /** * The class constructor. * * @param int $cmid The database module id + * @param \action_menu|null $actionsselect The presets actions selector object. */ - public function __construct(int $cmid) { + public function __construct(int $cmid, ?\action_menu $actionsselect) { $this->cmid = $cmid; + $this->actionsselect = $actionsselect; } /** @@ -48,12 +52,14 @@ class presets_action_bar implements templatable, renderable { * @return array */ public function export_for_template(\renderer_base $output): array { - $importpresetlink = new moodle_url('/mod/data/preset.php', [ - 'id' => $this->cmid, 'action' => 'import' - ]); - return [ + $data = [ 'id' => $this->cmid, - 'importpreseturl' => $importpresetlink->out(false), ]; + + if ($this->actionsselect) { + $data['actionsselect'] = $this->actionsselect->export_for_template($output); + } + + return $data; } } diff --git a/mod/data/classes/output/templates_action_bar.php b/mod/data/classes/output/templates_action_bar.php index 4bee810045b..5d6f68cef58 100644 --- a/mod/data/classes/output/templates_action_bar.php +++ b/mod/data/classes/output/templates_action_bar.php @@ -16,6 +16,7 @@ namespace mod_data\output; +use core\output\select_menu; use templatable; use renderable; @@ -31,29 +32,25 @@ class templates_action_bar implements templatable, renderable { /** @var int $id The database module id. */ private $id; - /** @var \url_select $urlselect The URL selector object. */ - private $urlselect; + /** @var select_menu $selectmenu The URL selector object. */ + private $selectmenu; - /** @var \single_button|null $urlselect The save as preset single button object. */ - private $saveaspresetbutton; - - /** @var \single_button|null $urlselect The export preset single button object. */ - private $exportpresetbutton; + /** @var \action_menu $actionsselect The presets actions selector object. */ + private $actionsselect; /** * The class constructor. * * @param int $id The database module id. - * @param \url_select $urlselect The URL selector object. - * @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 select_menu $selectmenu The URL selector object. + * @param null $unused1 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param null $unused2 This parameter has been deprecated since 4.1 and should not be used anymore. + * @param \action_menu $actionsselect The presets actions selector object. */ - public function __construct(int $id, \url_select $urlselect, ?\single_button $saveaspresetbutton, - ?\single_button $exportpresetbutton) { + public function __construct(int $id, select_menu $selectmenu, $unused1, $unused2, \action_menu $actionsselect) { $this->id = $id; - $this->urlselect = $urlselect; - $this->saveaspresetbutton = $saveaspresetbutton; - $this->exportpresetbutton = $exportpresetbutton; + $this->selectmenu = $selectmenu; + $this->actionsselect = $actionsselect; } /** @@ -64,17 +61,10 @@ class templates_action_bar implements templatable, renderable { */ public function export_for_template(\renderer_base $output): array { - $data = [ + return [ 'd' => $this->id, - 'urlselect' => $this->urlselect->export_for_template($output), + 'selectmenu' => $this->selectmenu->export_for_template($output), + 'actionsselect' => $this->actionsselect->export_for_template($output), ]; - - $data['saveaspreset'] = $this->saveaspresetbutton; - - if ($this->exportpresetbutton) { - $data['exportpreset'] = $this->exportpresetbutton->export_for_template($output); - } - - return $data; } } diff --git a/mod/data/classes/output/view_action_bar.php b/mod/data/classes/output/view_action_bar.php index 24c21c451cc..d54d9601f01 100644 --- a/mod/data/classes/output/view_action_bar.php +++ b/mod/data/classes/output/view_action_bar.php @@ -16,7 +16,10 @@ namespace mod_data\output; +use data_portfolio_caller; +use mod_data\manager; use moodle_url; +use portfolio_add_button; use templatable; use renderable; @@ -38,17 +41,22 @@ class view_action_bar implements templatable, renderable { /** @var bool $hasentries Whether entries exist. */ private $hasentries; + /** @var bool $mode The current view mode (list, view...). */ + private $mode; + /** * The class constructor. * * @param int $id The database module id. * @param \url_select $urlselect The URL selector object. * @param bool $hasentries Whether entries exist. + * @param string $mode The current view mode (list, view...). */ - public function __construct(int $id, \url_select $urlselect, bool $hasentries) { + public function __construct(int $id, \url_select $urlselect, bool $hasentries, string $mode) { $this->id = $id; $this->urlselect = $urlselect; $this->hasentries = $hasentries; + $this->mode = $mode; } /** @@ -58,26 +66,81 @@ class view_action_bar implements templatable, renderable { * @return array */ public function export_for_template(\renderer_base $output): array { - global $PAGE; + global $PAGE, $DB, $CFG; $data = [ 'urlselect' => $this->urlselect->export_for_template($output), ]; - if (has_capability('mod/data:manageentries', $PAGE->context)) { - $importentrieslink = new moodle_url('/mod/data/import.php', - ['d' => $this->id, 'backto' => $PAGE->url->out(false)]); - $importentriesbutton = new \single_button($importentrieslink, - get_string('importentries', 'mod_data'), 'get', false); - $data['importentriesbutton'] = $importentriesbutton->export_for_template($output); + $activity = $DB->get_record('data', ['id' => $this->id], '*', MUST_EXIST); + $manager = manager::create_from_instance($activity); + + $actionsselect = null; + // Import entries. + if (has_capability('mod/data:manageentries', $manager->get_context())) { + $actionsselect = new \action_menu(); + $actionsselect->set_menu_trigger(get_string('actions'), 'btn btn-secondary'); + + $importentrieslink = new moodle_url('/mod/data/import.php', ['d' => $this->id, 'backto' => $PAGE->url->out(false)]); + $actionsselect->add(new \action_menu_link( + $importentrieslink, + null, + get_string('importentries', 'mod_data'), + false + )); } - if (has_capability(DATA_CAP_EXPORT, $PAGE->context) && $this->hasentries) { - $exportentrieslink = new moodle_url('/mod/data/export.php', - ['d' => $this->id, 'backto' => $PAGE->url->out(false)]); - $exportentriesbutton = new \single_button($exportentrieslink, get_string('exportentries', 'mod_data'), - 'get', false); - $data['exportentriesbutton'] = $exportentriesbutton->export_for_template($output); + // Export entries. + if (has_capability(DATA_CAP_EXPORT, $manager->get_context()) && $this->hasentries) { + if (!$actionsselect) { + $actionsselect = new \action_menu(); + $actionsselect->set_menu_trigger(get_string('actions'), 'btn btn-secondary'); + } + $exportentrieslink = new moodle_url('/mod/data/export.php', ['d' => $this->id, 'backto' => $PAGE->url->out(false)]); + $actionsselect->add(new \action_menu_link( + $exportentrieslink, + null, + get_string('exportentries', 'mod_data'), + false + )); + } + + // Export to portfolio. This is for exporting all records, not just the ones in the search. + if ($this->mode == '' && !empty($CFG->enableportfolios) && $this->hasentries) { + if ($manager->can_export_entries()) { + // Add the portfolio export button. + require_once($CFG->libdir . '/portfoliolib.php'); + + $cm = $manager->get_coursemodule(); + + $button = new portfolio_add_button(); + $button->set_callback_options( + 'data_portfolio_caller', + ['id' => $cm->id], + 'mod_data' + ); + if (data_portfolio_caller::has_files($activity)) { + // No plain HTML. + $button->set_formats([PORTFOLIO_FORMAT_RICHHTML, PORTFOLIO_FORMAT_LEAP2A]); + } + $exporturl = $button->to_html(PORTFOLIO_ADD_MOODLE_URL); + if (!is_null($exporturl)) { + if (!$actionsselect) { + $actionsselect = new \action_menu(); + $actionsselect->set_menu_trigger(get_string('actions'), 'btn btn-secondary'); + } + $actionsselect->add(new \action_menu_link( + $exporturl, + null, + get_string('addtoportfolio', 'portfolio'), + false + )); + } + } + } + + if ($actionsselect) { + $data['actionsselect'] = $actionsselect->export_for_template($output); } return $data; diff --git a/mod/data/classes/output/zero_state_action_bar.php b/mod/data/classes/output/zero_state_action_bar.php index 5c4632a5237..f17b6d125dd 100644 --- a/mod/data/classes/output/zero_state_action_bar.php +++ b/mod/data/classes/output/zero_state_action_bar.php @@ -59,7 +59,7 @@ class zero_state_action_bar implements templatable, renderable { $usepresetlink = new moodle_url('/mod/data/preset.php', $params); $usepresetbutton = new \single_button($usepresetlink, - get_string('usepreset', 'mod_data'), 'get', true); + get_string('usestandard', 'mod_data'), 'get', true); $data['usepresetbutton'] = $usepresetbutton->export_for_template($output); $actionbar = new \mod_data\output\action_bar($instance->id, $PAGE->url); @@ -69,7 +69,7 @@ class zero_state_action_bar implements templatable, renderable { $params['action'] = 'import'; $importpresetlink = new moodle_url('/mod/data/preset.php', $params); $importpresetbutton = new \single_button($importpresetlink, - get_string('importpreset', 'mod_data'), 'get', false, [ + get_string('importapreset', 'mod_data'), 'get', false, [ 'data-action' => 'importpresets', 'data-dataid' => $cm->id, ]); @@ -79,4 +79,3 @@ class zero_state_action_bar implements templatable, renderable { return $data; } } - diff --git a/mod/data/classes/preset.php b/mod/data/classes/preset.php index 334bacdb14c..fdad67ef147 100644 --- a/mod/data/classes/preset.php +++ b/mod/data/classes/preset.php @@ -576,7 +576,10 @@ class preset { * @return string The plugin preset name to display. */ public static function get_name_from_plugin(string $pluginname): string { - if (get_string_manager()->string_exists('modulename', 'datapreset_'.$pluginname)) { + if ($pos = strpos($pluginname, '/')) { + $pluginname = substr($pluginname, $pos + 1); + } + if (!strpos(trim($pluginname), ' ') && get_string_manager()->string_exists('modulename', 'datapreset_'.$pluginname)) { return get_string('modulename', 'datapreset_'.$pluginname); } else { return $pluginname; diff --git a/mod/data/data.js b/mod/data/data.js index 871de649b83..12dfc501743 100644 --- a/mod/data/data.js +++ b/mod/data/data.js @@ -23,20 +23,23 @@ function insert_field_tags(selectlist) { */ function showHideAdvSearch(checked) { var divs = document.getElementsByTagName('div'); - for(i=0;iget_fields_action_bar(true, true, true); + $fieldactionbar = $actionbar->get_fields_action_bar(true); data_print_header($course, $cm, $data, 'fields', $fieldactionbar); - echo $OUTPUT->heading(get_string('managefields', 'data'), 2, 'mb-4'); + echo $OUTPUT->box_start('mb-4'); + echo get_string('fieldshelp', 'data'); + echo $OUTPUT->box_end(); $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]; + $table->responsive = false; $fieldrecords = $manager->get_field_records(); $missingfieldtypes = []; @@ -356,26 +359,40 @@ if (($mode == 'new') && (!empty($newtype))) { // Adding a new field. 'mode' => 'delete', )); + $actionmenu = new action_menu(); + $icon = $OUTPUT->pix_icon('i/menu', get_string('actions')); + $actionmenu->set_menu_trigger($icon, 'btn btn-icon d-flex align-items-center justify-content-center'); + $actionmenu->set_action_label(get_string('actions')); + $actionmenu->attributes['class'] .= ' fields-actions'; + // 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; + // Edit icon, only displayed when the field type is known. + $actionmenu->add(new action_menu_link_secondary( + $displayurl, + null, + get_string('edit'), + )); } + // Delete. + $actionmenu->add(new action_menu_link_secondary( + $deleteurl, + null, + get_string('delete'), + )); + $actionmenutemplate = $actionmenu->export_for_template($OUTPUT); + $table->data[] = [ - $fieldnamedata, + $field->field->name, $fieltypedata, $field->field->required ? get_string('yes') : get_string('no'), shorten_text($field->field->description, 30), - $fieldlinkdata + $OUTPUT->render_from_template('core/action_menu', $actionmenutemplate) ]; if (!empty($missingfieldtypes)) { diff --git a/mod/data/lang/en/data.php b/mod/data/lang/en/data.php index 6e1bb8af354..b8512723676 100644 --- a/mod/data/lang/en/data.php +++ b/mod/data/lang/en/data.php @@ -132,7 +132,7 @@ $string['editcomment'] = 'Edit comment'; $string['editentry'] = 'Edit entry'; $string['editfield'] = 'Edit field'; $string['editordisable'] = 'Disable editor'; -$string['editorenable'] = 'Enable editor'; +$string['editorenable'] = 'Enable code editor'; $string['editpreset'] = 'Edit preset'; $string['emptyadd'] = 'The Add template is empty, generating a default form...'; $string['emptyaddform'] = 'You did not fill out any fields!'; @@ -185,6 +185,7 @@ $string['fieldnametype'] = '{$a->name} ({$a->type})'; $string['fieldnotmatched'] = 'The following fields in your file are not known in this database: {$a}'; $string['fieldoptions'] = 'Options (one per line)'; $string['fields'] = 'Fields'; +$string['fieldshelp'] = 'Create fields to collect different types of data for your entries or customise the existing ones if you used a preset.'; $string['fieldsnavigation'] = 'Fields tertiary navigation'; $string['fieldupdated'] = 'Field updated'; $string['fieldwidth'] = 'Width'; @@ -195,8 +196,8 @@ $string['filesnotgenerated'] = 'Not all files were generated: {$a}'; $string['filtername'] = 'Database auto-linking'; $string['footer'] = 'Footer'; $string['forcelinkname'] = 'Forced name for the link'; -$string['foundnorecords'] = 'No records found (Reset filters)'; -$string['foundrecords'] = 'Found records: {$a->num}/{$a->max} (Reset filters)'; +$string['foundnorecords'] = 'No records found. Clear all'; +$string['foundrecords'] = 'Found {$a->num} out of {$a->max} records. Clear all'; $string['fromfile'] = 'Import from zip file'; $string['fromfile_help'] = 'The import from zip file feature allows you to browse for and upload a preset zip of templates and fields.'; $string['generateerror'] = 'Not all files generated!'; @@ -216,7 +217,8 @@ $string['chooseorupload'] = 'Choose file'; $string['choosepreset'] = 'Preset file'; $string['expired'] = 'Sorry, this activity closed on {$a} and is no longer available'; $string['importentries'] = 'Import entries'; -$string['importpreset'] = 'Import a preset'; +$string['importpreset'] = 'Import preset'; +$string['importapreset'] = 'Import a preset'; $string['importsuccess'] = 'The preset has been successfully applied.'; $string['importpresetmissingcapability'] = 'You don\'t have permission to import a preset.'; $string['includeapproval'] = 'Include approval status'; @@ -261,7 +263,7 @@ $string['latlonglinkservicesdisplayed'] = 'Link-out services to display'; $string['latlongotherfields'] = 'Other fields'; $string['list'] = 'View list'; $string['listview'] = 'List view'; -$string['listtemplate'] = 'List template'; +$string['listtemplate'] = 'List view template'; $string['longitude'] = 'Longitude'; $string['manageapproved'] = 'Allow editing of approved entries'; $string['managefields'] = 'Manage fields'; @@ -307,7 +309,7 @@ $string['nodefinedfields'] = 'New preset has no defined fields!'; $string['nofieldcontent'] = 'Field content not found'; $string['nofieldindatabase'] = 'There are no fields defined for this database.'; $string['nofields'] = 'No fields yet'; -$string['nolisttemplate'] = 'List template is not yet defined'; +$string['nolisttemplate'] = 'List view template is not yet defined'; $string['nomatch'] = 'No matching entries found!'; $string['nomaximum'] = 'No maximum'; $string['nopreviewavailable'] = 'No preview available for {$a}'; @@ -341,7 +343,7 @@ $string['presetinfo'] = 'Saving as a preset will publish this template. Other us $string['presetnotselected'] = 'No preset has been selected.'; $string['presets'] = 'Presets'; $string['presetshelp'] = 'Choose a preset to use as a starting point.'; -$string['preview'] = 'Preview'; +$string['preview'] = 'Preview of {$a}'; $string['privacy:metadata:commentpurpose'] = 'Comments on database records'; $string['privacy:metadata:data_content'] = 'Represents one answer to one field in database activity module'; $string['privacy:metadata:data_content:fieldid'] = 'Field definition ID'; @@ -394,7 +396,7 @@ $string['rsstype'] = 'RSS feed for this activity'; $string['save'] = 'Save'; $string['saveandadd'] = 'Save and add another'; $string['saveandview'] = 'Save and view'; -$string['saveaspreset'] = 'Save as preset'; +$string['saveaspreset'] = 'Publish preset on this site'; $string['saveaspreset_help'] = 'The save as preset feature publishes the templates and fields as a preset which others on the site can then use. (You may delete it from the list of presets at any time.)'; $string['savedataaspreset'] = 'Save all fields and templates as preset'; $string['saveaspresetmissingcapability'] = 'The user does not have permission to save the database as a preset.'; @@ -410,7 +412,7 @@ $string['showall'] = 'Show all entries'; $string['showmore'] = 'Show more'; $string['single'] = 'View single'; $string['singleview'] = 'Single view'; -$string['singletemplate'] = 'Single template'; +$string['singletemplate'] = 'Single view template'; $string['startbuilding'] = 'Start building your activity'; $string['subplugintype_datafield'] = 'Database field type'; $string['subplugintype_datafield_plural'] = 'Database field types'; @@ -447,7 +449,7 @@ $string['uploadrecords_link'] = 'mod/data/import'; $string['url'] = 'URL'; $string['usedate'] = 'Include in search.'; $string['usepredefinedset'] = 'Use predefined set'; -$string['usepreset'] = 'Use a preset'; +$string['usepreset'] = 'Use this preset'; $string['usestandard'] = 'Use a preset'; $string['usestandard_help'] = 'To use a preset available to the whole site, select it from the list. (If you have added a preset to the list using the save as preset feature then you have the option of deleting it.)'; $string['viewfromdate'] = 'Read only from'; @@ -462,8 +464,8 @@ $string['unsupportedexport'] = '({$a->fieldtype}) cannot be exported.'; // Deprecated since Moodle 4.1. $string['buttons'] = 'Actions'; -$string['nolisttemplate'] = 'List template is not yet defined'; -$string['nosingletemplate'] = 'Single template is not yet defined'; +$string['nolisttemplate'] = 'List view template is not yet defined'; +$string['nosingletemplate'] = 'Single view template is not yet defined'; $string['pleaseaddsome'] = 'Please create some below or choose a predefined set to get started.'; $string['blank'] = 'Blank'; $string['savetemplate'] = 'Save template'; diff --git a/mod/data/lib.php b/mod/data/lib.php index 6b0de3b1a0a..a80dc425439 100644 --- a/mod/data/lib.php +++ b/mod/data/lib.php @@ -606,12 +606,7 @@ class data_field_base { // Base class for Database Field Types (see field/*/ function image() { global $OUTPUT; - $params = array('d'=>$this->data->id, 'fid'=>$this->field->id, 'mode'=>'display', 'sesskey'=>sesskey()); - $link = new moodle_url('/mod/data/field.php', $params); - $str = ''; - $str .= $OUTPUT->pix_icon('field/' . $this->type, $this->type, 'data'); - $str .= ''; - return $str; + return $OUTPUT->pix_icon('field/' . $this->type, $this->type, 'data'); } /** @@ -1669,8 +1664,9 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order=' $cm = get_coursemodule_from_instance('data', $data->id); $context = context_module::instance($cm->id); - echo '
'; + echo '
'; echo '
'; + echo '
'; echo '
'; echo ''; if ($mode =='asearch') { @@ -1750,7 +1746,12 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order=' echo ' ' . ''; + echo '
'; + echo '
'; echo ' '; + echo '
'; + echo '
'; + echo '
'; echo '
'; echo '
'; @@ -1833,9 +1834,9 @@ function data_print_preference_form($data, $perpage, $search, $sort='', $order=' ''; echo ''; echo '
'; - echo '
'; echo '
'; echo '
'; + echo '
'; } /** @@ -3525,11 +3526,11 @@ function data_extend_settings_navigation(settings_navigation $settings, navigati $defaultemplate = 'singletemplate'; } + $datanode->add(get_string('presets', 'data'), new moodle_url('/mod/data/preset.php', array('d' => $data->id))); $datanode->add(get_string('fields', 'data'), new moodle_url('/mod/data/field.php', array('d' => $data->id))); $datanode->add(get_string('templates', 'data'), new moodle_url('/mod/data/templates.php', array('d' => $data->id))); - $datanode->add(get_string('presets', 'data'), new moodle_url('/mod/data/preset.php', array('d' => $data->id))); } if (!empty($CFG->enablerssfeeds) && !empty($CFG->data_enablerssfeeds) && $data->rssarticles > 0) { diff --git a/mod/data/preset.php b/mod/data/preset.php index 2aba66f36cb..f6bed5f6c6a 100644 --- a/mod/data/preset.php +++ b/mod/data/preset.php @@ -146,7 +146,6 @@ if ($action === 'preview') { echo $OUTPUT->header(); $actionbar = new action_bar($data->id, $url); echo $actionbar->get_presets_preview_action_bar($manager, $fullname, $templatename); - echo $OUTPUT->heading(ucfirst($preset->name), 2, 'mb-4'); echo $renderer->render($preview); echo $OUTPUT->footer(); exit(0); @@ -170,7 +169,6 @@ if ($action === 'finishimport') { $actionbar = new \mod_data\output\action_bar($data->id, $url); echo $actionbar->get_presets_action_bar(); -echo $OUTPUT->heading(get_string('presets', 'data'), 2, 'mb-4'); $presets = new \mod_data\output\presets($manager, $presets, new \moodle_url('/mod/data/field.php'), true); echo $renderer->render_presets($presets); diff --git a/mod/data/preset/imagegallery/tests/behat/imagegallery_preset.feature b/mod/data/preset/imagegallery/tests/behat/imagegallery_preset.feature index eb8c25a3ca4..1ecbc74e41b 100644 --- a/mod/data/preset/imagegallery/tests/behat/imagegallery_preset.feature +++ b/mod/data/preset/imagegallery/tests/behat/imagegallery_preset.feature @@ -22,7 +22,7 @@ Feature: Users can use the Image gallery preset And I am on the "Mountain landscapes" "data activity" page logged in as teacher1 And I follow "Presets" And I click on "fullname" "radio" in the "Image gallery" "table_row" - And I click on "Use a preset" "button" + And I click on "Use this preset" "button" And the following "mod_data > entries" exist: | database | user | title | description | image | | data1 | student1 | First image | This is the description text for image 1 | first.png | @@ -73,12 +73,12 @@ Feature: Users can use the Image gallery preset And I should see "First name" And I should see "Last name" And I set the field "title" to "First image" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" Then I should see "First image" And I should not see "Second image" But I set the field "title" to "image" And I set the field "Order" to "Descending" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" And "Second image" "text" should appear before "First image" "text" @javascript diff --git a/mod/data/preset/journal/tests/behat/journal_preset.feature b/mod/data/preset/journal/tests/behat/journal_preset.feature index eb86652888b..6fcc27aff9b 100644 --- a/mod/data/preset/journal/tests/behat/journal_preset.feature +++ b/mod/data/preset/journal/tests/behat/journal_preset.feature @@ -22,7 +22,7 @@ Feature: Users can use the Journal preset And I am on the "Student reflections" "data activity" page logged in as teacher1 And I follow "Presets" And I click on "fullname" "radio" in the "Journal" "table_row" - And I click on "Use a preset" "button" + And I click on "Use this preset" "button" And the following "mod_data > entries" exist: | database | user | Title | Content | | data1 | student1 | Reflection created by student | This is the content for the entry 1 | @@ -59,12 +59,12 @@ Feature: Users can use the Journal preset And I should see "First name" And I should see "Last name" And I set the field "Title" to "student" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" Then I should see "Reflection created by student" And I should not see "Reflection created by teacher" But I set the field "Title" to "Reflection" And I set the field "Order" to "Descending" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" And "Reflection created by teacher" "text" should appear before "Reflection created by student" "text" @javascript diff --git a/mod/data/preset/proposals/tests/behat/proposals_preset.feature b/mod/data/preset/proposals/tests/behat/proposals_preset.feature index 9d7c43c1abf..c15ff161482 100644 --- a/mod/data/preset/proposals/tests/behat/proposals_preset.feature +++ b/mod/data/preset/proposals/tests/behat/proposals_preset.feature @@ -22,7 +22,7 @@ Feature: Users can use the Proposals preset And I am on the "Student projects" "data activity" page logged in as teacher1 And I follow "Presets" And I click on "fullname" "radio" in the "Proposals" "table_row" - And I click on "Use a preset" "button" + And I click on "Use this preset" "button" And the following "mod_data > entries" exist: | database | user | Title | Summary | Content | Status | | data1 | student1 | Project created by student | Summary 1 | Content for entry 1 | Pending | @@ -73,12 +73,12 @@ Feature: Users can use the Proposals preset And I should see "First name" And I should see "Last name" And I set the field "Title" to "student" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" Then I should see "Project created by student" And I should not see "Project created by teacher" But I set the field "Title" to "Project" And I set the field "Order" to "Descending" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" And "Project created by teacher" "text" should appear before "Project created by student" "text" @javascript diff --git a/mod/data/preset/resources/tests/behat/resources_preset.feature b/mod/data/preset/resources/tests/behat/resources_preset.feature index 0f36842a7bb..6d546829be3 100644 --- a/mod/data/preset/resources/tests/behat/resources_preset.feature +++ b/mod/data/preset/resources/tests/behat/resources_preset.feature @@ -22,7 +22,7 @@ Feature: Users can use the Resources preset And I am on the "Student resources" "data activity" page logged in as teacher1 And I follow "Presets" And I click on "fullname" "radio" in the "Resources" "table_row" - And I click on "Use a preset" "button" + And I click on "Use this preset" "button" And the following "mod_data > entries" exist: | database | user | Title | Description | Type | Author | Web link | Cover | | data1 | student1 | My favourite book | Book content | Type1 | The book author | http://myfavouritebook.cat | first.png | @@ -77,12 +77,12 @@ Feature: Users can use the Resources preset And I should see "First name" And I should see "Last name" And I set the field "Title" to "book" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" Then I should see "My favourite book" And I should not see "My favourite podcast" But I set the field "Title" to "favourite" And I set the field "Order" to "Descending" - And I press "Save settings" + And I click on "Save settings" "button" in the "data_adv_form" "region" And "My favourite podcast" "text" should appear before "My favourite book" "text" @javascript diff --git a/mod/data/styles.css b/mod/data/styles.css index 1e9ace58ee6..3102d3d21c7 100644 --- a/mod/data/styles.css +++ b/mod/data/styles.css @@ -150,7 +150,8 @@ } .preset_action_menu .dropdown-toggle::after, -.entry-actionsmenu .dropdown-toggle::after { +.entry-actionsmenu .dropdown-toggle::after, +.fields-actions .dropdown-toggle::after { display: none; } @@ -189,6 +190,13 @@ pointer-events: none; } +/* Actions menu */ +.presetsactions .dropdown-toggle, +.presetsactions .dropdown-toggle:hover, +.presetsactions .show > .btn-secondary.dropdown-toggle, +.entriesactions .dropdown-toggle, +.entriesactions .dropdown-toggle:hover, +.entriesactions .show > .btn-secondary.dropdown-toggle, #page-mod-data-view .whitebutton .btn-secondary, #page-mod-data-field- .whitebutton .btn-secondary, #page-mod-data-templates .whitebutton .btn-secondary { diff --git a/mod/data/templates.php b/mod/data/templates.php index c76011f1451..d936d226af1 100644 --- a/mod/data/templates.php +++ b/mod/data/templates.php @@ -30,7 +30,7 @@ require_once('lib.php'); $id = optional_param('id', 0, PARAM_INT); // course module id $d = optional_param('d', 0, PARAM_INT); // database id -$mode = optional_param('mode', 'listtemplate', PARAM_ALPHA); +$mode = optional_param('mode', 'addtemplate', PARAM_ALPHA); $useeditor = optional_param('useeditor', null, PARAM_BOOL); $url = new moodle_url('/mod/data/templates.php'); @@ -85,8 +85,6 @@ if (!$manager->has_fields()) { $actionbar = new \mod_data\output\action_bar($instance->id, $url); echo $actionbar->get_templates_action_bar(); -echo $OUTPUT->heading(get_string($mode, 'data'), 2, 'mb-4'); - if (($formdata = data_submitted()) && confirm_sesskey()) { $notificationstr = get_string('templatesaved', 'data'); if (!empty($formdata->defaultform)) { diff --git a/mod/data/templates/action_bar.mustache b/mod/data/templates/action_bar.mustache index 54e2f09fb0b..1f8fe7c1579 100644 --- a/mod/data/templates/action_bar.mustache +++ b/mod/data/templates/action_bar.mustache @@ -84,34 +84,35 @@
{{#hasback}} -