mirror of
https://github.com/moodle/moodle.git
synced 2025-03-14 12:40:01 +01:00
MDL-76358 mod_data: Add options to preset menu
* Add "Preview" and "Use this preset" menus to the preset plugin page's burger menu * Refactor importmapping dialogue to use the 'data-action' selector * Add a new set_kebab_trigger action menu method * Use set_additional_classes method for action menu * Remove redundant parameter to add_action_menu
This commit is contained in:
parent
b8b905cd90
commit
45317d6db5
@ -128,9 +128,7 @@ class controlmenu implements named_templatable, renderable {
|
||||
|
||||
// Convert control array into an action_menu.
|
||||
$menu = new action_menu();
|
||||
$icon = $output->pix_icon('i/menu', get_string('edit'));
|
||||
$menu->set_menu_trigger($icon, 'btn btn-icon d-flex align-items-center justify-content-center');
|
||||
|
||||
$menu->set_kebab_trigger(get_string('edit'));
|
||||
$menu->attributes['class'] .= ' section-cm-edit-actions commands';
|
||||
|
||||
// Prioritise the menu ahead of all other actions.
|
||||
|
@ -82,8 +82,7 @@ class controlmenu implements named_templatable, renderable {
|
||||
|
||||
// Convert control array into an action_menu.
|
||||
$menu = new action_menu();
|
||||
$icon = $output->pix_icon('i/menu', get_string('edit'));
|
||||
$menu->set_menu_trigger($icon, 'btn btn-icon d-flex align-items-center justify-content-center');
|
||||
$menu->set_kebab_trigger(get_string('edit'));
|
||||
$menu->attributes['class'] .= ' section-actions';
|
||||
foreach ($controls as $value) {
|
||||
$url = empty($value['url']) ? '' : $value['url'];
|
||||
|
@ -4304,6 +4304,31 @@ class action_menu implements renderable, templatable {
|
||||
$this->triggerextraclasses = $extraclasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes for the trigger menu
|
||||
*/
|
||||
const DEFAULT_KEBAB_TRIGGER_CLASSES = 'btn btn-icon d-flex align-items-center justify-content-center';
|
||||
|
||||
/**
|
||||
* Setup trigger as in the kebab menu.
|
||||
*
|
||||
* @param string|null $triggername
|
||||
* @param core_renderer|null $output
|
||||
* @param string|null $extraclasses extra classes for the trigger {@see self::set_menu_trigger()}
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function set_kebab_trigger(?string $triggername = null, ?core_renderer $output = null,
|
||||
?string $extraclasses = '') {
|
||||
global $OUTPUT;
|
||||
if (empty($output)) {
|
||||
$output = $OUTPUT;
|
||||
}
|
||||
$label = $triggername ?? get_string('actions');
|
||||
$triggerclasses = self::DEFAULT_KEBAB_TRIGGER_CLASSES . ' ' . $extraclasses;
|
||||
$icon = $output->pix_icon('i/menu', $label);
|
||||
$this->set_menu_trigger($icon, $triggerclasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there is at least one visible link in the menu.
|
||||
*
|
||||
|
@ -14,6 +14,7 @@ information provided here is intended especially for developers.
|
||||
* New DB parameter 'versionfromdb', only available for MySQL and MariaDB drivers. It allows to force the DB version to be
|
||||
evaluated through an explicit call to VERSION() to skip the PHP client version which appears to be sometimes fooled by the
|
||||
underlying infrastructure, e.g. PaaS on Azure.
|
||||
* The actionmenu component has now a set_kebab_trigger that will setup the action menu for use in kebab menus.
|
||||
* The useexternalyui configuration setting has been removed as a part of the migration away from YUI.
|
||||
It only worked with http sites and did not officially support SSL, and is at risk of disappearing should Yahoo! decide
|
||||
to remove it.
|
||||
@ -715,7 +716,6 @@ filepath because some components, such as mod_page or mod_resource, add the revi
|
||||
call the above function because the file is sent by a third party library, then you should add
|
||||
the attribute data-double-submit-protection="off" to your form.
|
||||
|
||||
|
||||
=== 3.7 ===
|
||||
|
||||
* Nodes in the navigation api can have labels for each group. See set/get_collectionlabel().
|
||||
|
@ -5,6 +5,6 @@ define("mod_data/importmappingdialogue",["exports","core/notification","core/aja
|
||||
* @module mod_data/importmappingdialogue
|
||||
* @copyright 2022 Amaia Anabitarte <amaia@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_ajax=_interopRequireDefault(_ajax),_url=_interopRequireDefault(_url),_templates=_interopRequireDefault(_templates),_modal_factory=_interopRequireDefault(_modal_factory),(0,_prefetch.prefetchStrings)("mod_data",["mapping:dialogtitle:usepreset"]);const selectors_selectPresetButton='input[name="selectpreset"]';_exports.init=()=>{registerEventListeners()};const registerEventListeners=()=>{document.addEventListener("click",(event=>{const usepreset=event.target.closest(selectors_selectPresetButton);usepreset&&(event.preventDefault(),showMappingDialogue(usepreset))}))},showMappingDialogue=usepreset=>{const presetName=usepreset.dataset.presetname,cmId=usepreset.dataset.cmid;getMappingInformation(cmId,presetName).then((result=>(result.data&&result.data.needsmapping?buildModal({title:(0,_str.get_string)("mapping:dialogtitle:usepreset","mod_data",result.data.presetname),body:_templates.default.render("mod_data/fields_mapping_body",result.data),footer:_templates.default.render("mod_data/fields_mapping_footer",getMappingButtons(cmId,presetName)),large:!0}):window.location.href=_url.default.relativeUrl("mod/data/field.php",{id:cmId,mode:"usepreset",fullname:presetName},!1),!0))).catch(_notification.default.exception)},buildModal=params=>_modal_factory.default.create({...params,type:_modal_factory.default.types.DEFAULT}).then((modal=>(modal.show(),modal.showFooter(),modal.registerCloseOnCancel(),modal))).catch(_notification.default.exception),getMappingButtons=(cmId,presetName)=>{const data={};return data.mapfieldsbutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"select"},!1),data.applybutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"notmapping"},!1),data},getMappingInformation=(cmId,presetName)=>{const request={methodname:"mod_data_get_mapping_information",args:{cmid:cmId,importedpreset:presetName}};return _ajax.default.call([request])[0]}}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_notification=_interopRequireDefault(_notification),_ajax=_interopRequireDefault(_ajax),_url=_interopRequireDefault(_url),_templates=_interopRequireDefault(_templates),_modal_factory=_interopRequireDefault(_modal_factory),(0,_prefetch.prefetchStrings)("mod_data",["mapping:dialogtitle:usepreset"]);const selectors_selectPreset='[data-action="selectpreset"]';_exports.init=()=>{registerEventListeners()};const registerEventListeners=()=>{document.addEventListener("click",(event=>{const preset=event.target.closest(selectors_selectPreset);preset&&(event.preventDefault(),showMappingDialogue(preset))}))},showMappingDialogue=usepreset=>{const presetName=usepreset.dataset.presetname,cmId=usepreset.dataset.cmid;getMappingInformation(cmId,presetName).then((result=>(result.data&&result.data.needsmapping?buildModal({title:(0,_str.get_string)("mapping:dialogtitle:usepreset","mod_data",result.data.presetname),body:_templates.default.render("mod_data/fields_mapping_body",result.data),footer:_templates.default.render("mod_data/fields_mapping_footer",getMappingButtons(cmId,presetName)),large:!0}):window.location.href=_url.default.relativeUrl("mod/data/field.php",{id:cmId,mode:"usepreset",fullname:presetName},!1),!0))).catch(_notification.default.exception)},buildModal=params=>_modal_factory.default.create({...params,type:_modal_factory.default.types.DEFAULT}).then((modal=>(modal.show(),modal.showFooter(),modal.registerCloseOnCancel(),modal))).catch(_notification.default.exception),getMappingButtons=(cmId,presetName)=>{const data={};return data.mapfieldsbutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"select"},!1),data.applybutton=_url.default.relativeUrl("mod/data/field.php",{id:cmId,fullname:presetName,mode:"usepreset",action:"notmapping"},!1),data},getMappingInformation=(cmId,presetName)=>{const request={methodname:"mod_data_get_mapping_information",args:{cmid:cmId,importedpreset:presetName}};return _ajax.default.call([request])[0]}}));
|
||||
|
||||
//# sourceMappingURL=importmappingdialogue.min.js.map
|
File diff suppressed because one or more lines are too long
@ -33,7 +33,7 @@ import {get_string as getString} from 'core/str';
|
||||
prefetchStrings('mod_data', ['mapping:dialogtitle:usepreset']);
|
||||
|
||||
const selectors = {
|
||||
selectPresetButton: 'input[name="selectpreset"]',
|
||||
selectPreset: '[data-action="selectpreset"]',
|
||||
};
|
||||
|
||||
/**
|
||||
@ -48,10 +48,10 @@ export const init = () => {
|
||||
*/
|
||||
const registerEventListeners = () => {
|
||||
document.addEventListener('click', (event) => {
|
||||
const usepreset = event.target.closest(selectors.selectPresetButton);
|
||||
if (usepreset) {
|
||||
const preset = event.target.closest(selectors.selectPreset);
|
||||
if (preset) {
|
||||
event.preventDefault();
|
||||
showMappingDialogue(usepreset);
|
||||
showMappingDialogue(preset);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -41,7 +41,7 @@ class presets implements templatable, renderable {
|
||||
/** @var array $presets The array containing the existing presets. */
|
||||
private $presets;
|
||||
|
||||
/** @var moodle_url $formactionurl The the action url for the form. */
|
||||
/** @var moodle_url $formactionurl The action url for the form. */
|
||||
private $formactionurl;
|
||||
|
||||
/** @var bool $manage Whether the manage preset options should be displayed. */
|
||||
@ -135,77 +135,103 @@ class presets implements templatable, renderable {
|
||||
private function get_preset_action_menu(renderer_base $output, $preset, ?int $userid): stdClass {
|
||||
|
||||
$actions = new stdClass();
|
||||
$actionmenu = null;
|
||||
$id = $this->manager->get_instance()->id;
|
||||
// Only presets saved by users can be edited or removed (so the datapreset plugins shouldn't display these buttons).
|
||||
if ($this->manage && !$preset->isplugin) {
|
||||
$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'] .= ' presets-actions';
|
||||
$cmid = $this->manager->get_coursemodule()->id;
|
||||
// If we cannot manage then return an empty menu.
|
||||
if (!$this->manage) {
|
||||
return $actions;
|
||||
}
|
||||
$actionmenu = new action_menu();
|
||||
$actionmenu->set_kebab_trigger();
|
||||
$actionmenu->set_action_label(get_string('actions'));
|
||||
$actionmenu->set_additional_classes('presets-actions');
|
||||
$canmanage = $preset->can_manage();
|
||||
|
||||
$canmanage = $preset->can_manage();
|
||||
$usepreseturl = new moodle_url('/mod/data/preset.php', [
|
||||
'action' => 'usepreset',
|
||||
'cmid' => $cmid,
|
||||
]);
|
||||
$this->add_action_menu($actionmenu, get_string('usepreset', 'mod_data'), $usepreseturl, [
|
||||
'data-action' => 'selectpreset',
|
||||
'data-presetname' => $preset->get_fullname(),
|
||||
'data-cmid' => $cmid,
|
||||
]
|
||||
);
|
||||
|
||||
// Attention: the id here is the cm->id, not d->id.
|
||||
$previewpreseturl = new moodle_url('/mod/data/preset.php', [
|
||||
'fullname' => $preset->get_fullname(),
|
||||
'action' => 'preview',
|
||||
'id' => $cmid,
|
||||
]);
|
||||
$this->add_action_menu($actionmenu, get_string('previewaction', 'mod_data'), $previewpreseturl, [
|
||||
'data-action' => 'preview',
|
||||
]
|
||||
);
|
||||
|
||||
// Presets saved by users can be edited or removed.
|
||||
if (!$preset->isplugin) {
|
||||
// Edit.
|
||||
if ($canmanage) {
|
||||
$params = [
|
||||
'd' => $id,
|
||||
$editactionurl = new moodle_url('/mod/data/preset.php', [
|
||||
'action' => 'edit',
|
||||
];
|
||||
$editactionurl = new moodle_url('/mod/data/preset.php', $params);
|
||||
$attributes = [
|
||||
'd' => $id,
|
||||
]);
|
||||
$this->add_action_menu($actionmenu, get_string('edit'), $editactionurl, [
|
||||
'data-action' => 'editpreset',
|
||||
'data-dataid' => $id,
|
||||
"data-presetname" => $preset->name,
|
||||
"data-presetdescription" => $preset->description,
|
||||
];
|
||||
$actionmenu->add(new action_menu_link_secondary(
|
||||
$editactionurl,
|
||||
null,
|
||||
get_string('edit'),
|
||||
$attributes
|
||||
));
|
||||
|
||||
]);
|
||||
}
|
||||
|
||||
// Export.
|
||||
$params = [
|
||||
'd' => $id,
|
||||
$exporturl = new moodle_url('/mod/data/preset.php', [
|
||||
'presetname' => $preset->name,
|
||||
'action' => 'export',
|
||||
];
|
||||
$exporturl = new moodle_url('/mod/data/preset.php', $params);
|
||||
$actionmenu->add(new action_menu_link_secondary(
|
||||
$exporturl,
|
||||
null,
|
||||
get_string('export', 'mod_data'),
|
||||
));
|
||||
'd' => $id,
|
||||
]);
|
||||
$this->add_action_menu($actionmenu, get_string('export', 'mod_data'), $exporturl, [
|
||||
'data-action' => 'exportpreset',
|
||||
"data-presetname" => $preset->name,
|
||||
"data-presetdescription" => $preset->description,
|
||||
]);
|
||||
|
||||
// Delete.
|
||||
if ($canmanage) {
|
||||
$params = [
|
||||
'd' => $id,
|
||||
|
||||
$deleteactionurl = new moodle_url('/mod/data/preset.php', [
|
||||
'action' => 'delete',
|
||||
];
|
||||
$deleteactionurl = new moodle_url('/mod/data/preset.php', $params);
|
||||
$attributes = [
|
||||
'd' => $id,
|
||||
]);
|
||||
$this->add_action_menu($actionmenu, get_string('delete'), $deleteactionurl, [
|
||||
'data-action' => 'deletepreset',
|
||||
'data-dataid' => $id,
|
||||
"data-presetname" => $preset->name,
|
||||
];
|
||||
$actionmenu->add(new action_menu_link_secondary(
|
||||
$deleteactionurl,
|
||||
null,
|
||||
get_string('delete'),
|
||||
$attributes,
|
||||
));
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_null($actionmenu)) {
|
||||
$actions = $actionmenu->export_for_template($output);
|
||||
}
|
||||
|
||||
$actions = $actionmenu->export_for_template($output);
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add action to the action menu
|
||||
*
|
||||
* @param action_menu $actionmenu
|
||||
* @param string $actionlabel
|
||||
* @param moodle_url $actionurl
|
||||
* @param array $otherattributes
|
||||
* @return void
|
||||
*/
|
||||
private function add_action_menu(action_menu &$actionmenu, string $actionlabel, moodle_url $actionurl,
|
||||
array $otherattributes) {
|
||||
$attributes = [
|
||||
'data-dataid' => $this->manager->get_instance()->id,
|
||||
];
|
||||
$actionmenu->add(new action_menu_link_secondary(
|
||||
$actionurl,
|
||||
null,
|
||||
$actionlabel,
|
||||
array_merge($attributes, $otherattributes),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -718,10 +718,9 @@ class template {
|
||||
global $OUTPUT, $CFG;
|
||||
|
||||
$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_kebab_trigger();
|
||||
$actionmenu->set_action_label(get_string('actions'));
|
||||
$actionmenu->attributes['class'] .= ' entry-actionsmenu';
|
||||
$actionmenu->set_additional_classes('entry-actionsmenu');
|
||||
|
||||
// Show more.
|
||||
if ($this->showmore) {
|
||||
|
@ -355,10 +355,9 @@ if (($mode == 'new') && (!empty($newtype))) { // Adding a new field.
|
||||
));
|
||||
|
||||
$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_kebab_trigger();
|
||||
$actionmenu->set_action_label(get_string('actions'));
|
||||
$actionmenu->attributes['class'] .= ' fields-actions';
|
||||
$actionmenu->set_additional_classes('fields-actions');
|
||||
|
||||
// It display a notification when the field type does not exist.
|
||||
if ($field->type === 'unknown') {
|
||||
|
@ -352,6 +352,7 @@ $string['presetnotselected'] = 'No preset has been selected.';
|
||||
$string['presets'] = 'Presets';
|
||||
$string['presetshelp'] = 'Choose a preset to use as a starting point.';
|
||||
$string['preview'] = 'Preview of {$a}';
|
||||
$string['previewaction'] = 'Preview';
|
||||
$string['privacy:metadata:commentpurpose'] = 'Comments on database records';
|
||||
$string['privacy:metadata:data_content'] = 'The content of a field';
|
||||
$string['privacy:metadata:data_content:fieldid'] = 'Field definition ID';
|
||||
|
@ -38,7 +38,7 @@
|
||||
<input type="hidden" name="mode" value="usepreset">
|
||||
<input type="hidden" name="action" value="select">
|
||||
<input type="hidden" name="fullname" value="{{userid}}/{{shortname}}">
|
||||
<input type="submit" name="selectpreset" value="{{#str}}usepreset, mod_data{{/str}}" class="btn btn-primary"
|
||||
<input type="submit" name="selectpreset" data-action="selectpreset" value="{{#str}}usepreset, mod_data{{/str}}" class="btn btn-primary"
|
||||
data-cmid="{{cmid}}" data-presetname="{{userid}}/{{shortname}}">
|
||||
</form>
|
||||
{{/ stickycontent }}
|
||||
|
@ -93,6 +93,7 @@
|
||||
<input
|
||||
type="submit"
|
||||
name="selectpreset"
|
||||
data-action="selectpreset"
|
||||
value="{{#str}}usepreset, mod_data{{/str}}"
|
||||
class="btn btn-secondary"
|
||||
disabled
|
||||
|
@ -1,8 +1,8 @@
|
||||
@mod @mod_data
|
||||
Feature: Users can view and manage data presets
|
||||
In order to use presets
|
||||
As a user
|
||||
I need to view, manage and use presets
|
||||
In order to use presets
|
||||
As a user
|
||||
I need to view, manage and use presets
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
@ -322,3 +322,31 @@ Feature: Users can view and manage data presets
|
||||
| user |
|
||||
| admin |
|
||||
| teacher1 |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Teachers can use "Use this preset" actions menu next to each preset.
|
||||
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
|
||||
And I follow "Presets"
|
||||
And I open the action menu in "<Preset Name>" "table_row"
|
||||
When I click on "Use this preset" "link" in the "<Preset Name>" "table_row"
|
||||
Then I should see "Preset applied"
|
||||
|
||||
Examples:
|
||||
| Preset Name |
|
||||
| Image gallery |
|
||||
| Saved preset 1 (Admin User) |
|
||||
| Saved preset by teacher1 (Teacher 1) |
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Teachers can use "Preview" actions menu next to each preset.
|
||||
Given I am on the "Mountain landscapes" "data activity" page logged in as teacher1
|
||||
And I follow "Presets"
|
||||
And I open the action menu in "<Preset Name>" "table_row"
|
||||
When I click on "Preview" "link" in the "<Preset Name>" "table_row"
|
||||
Then I should see "Preview of <Preset preview name>"
|
||||
|
||||
Examples:
|
||||
| Preset Name | Preset preview name |
|
||||
| Image gallery | Image gallery |
|
||||
| Saved preset 1 (Admin User) | Saved preset 1 |
|
||||
| Saved preset by teacher1 (Teacher 1) | Saved preset by teacher1 |
|
||||
|
Loading…
x
Reference in New Issue
Block a user