diff --git a/lib/classes/output/local/dropdown/status.php b/lib/classes/output/local/dropdown/status.php new file mode 100644 index 00000000000..0d2f5f2702d --- /dev/null +++ b/lib/classes/output/local/dropdown/status.php @@ -0,0 +1,100 @@ +. + +namespace core\output\local\dropdown; + +use core\output\choicelist; + +/** + * Class to render a dropdown dialog element. + * + * A dropdown dialog allows to render any arbitrary HTML into a dropdown elements triggered + * by a button. + * + * @package core + * @category output + * @copyright 2023 Ferran Recio + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class status extends dialog { + + /** + * @var choicelist content of dialog. + */ + protected $choices = null; + + /** + * Constructor. + * + * The definition object could contain the following keys: + * - classes: component CSS classes. + * - buttonclasses: the button CSS classes. + * - dialogwidth: the dropdown width. + * - extras: extra HTML attributes (attribute => value). + * + * @param string $buttoncontent the button content + * @param choicelist $choices the choice object + * @param array $definition an optional array of the element definition + */ + public function __construct(string $buttoncontent, choicelist $choices, array $definition = []) { + parent::__construct($buttoncontent, '', $definition); + $this->set_choice($choices); + } + + /** + * Set the dialog contents. + * + * @param choicelist $choices + */ + public function set_choice(choicelist $choices) { + $this->choices = $choices; + $description = $choices->get_description(); + if (!empty($description)) { + $this->set_content($description); + } + } + + /** + * Export this data so it can be used as the context for a mustache template (core/inplace_editable). + * + * @param \renderer_base $output typically, the renderer that's calling this function + * @return array data context for a mustache template + */ + public function export_for_template(\renderer_base $output): array { + $data = parent::export_for_template($output); + if ($this->choices !== null) { + $data['choices'] = $this->choices->export_for_template($output); + } + $selectedvalue = $this->choices->get_selected_value(); + if ($selectedvalue !== null) { + $data['extras'][] = (object)[ + 'attribute' => 'data-value', + 'value' => $selectedvalue, + ]; + } + return $data; + } + + /** + * Get the name of the template to use for this templatable. + * + * @param \renderer_base $renderer The renderer requesting the template name + * @return string the template name + */ + public function get_template_name(\renderer_base $renderer): string { + return 'core/local/dropdown/status'; + } +} diff --git a/lib/templates/local/dropdown/status.mustache b/lib/templates/local/dropdown/status.mustache new file mode 100644 index 00000000000..e0801a6c337 --- /dev/null +++ b/lib/templates/local/dropdown/status.mustache @@ -0,0 +1,153 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template core/local/dropdown/status + + Displays a dropdown status selector component. + + Classes required for JS: + * none + + Context variables required for this template: + * buttoncontent String - the dropdown trigger button content. + * choices Array - the status options. + + Example context (json): + { + "buttonid" : "someinternalid", + "buttoncontent" : "Trigger button", + "choices" : { + "hasoptions": true, + "dialogcontent": "Dialog content", + "options": [ + { + "optionid": "option1", + "value": "value1", + "name": "First option", + "description": "First option description", + "hasicon": false, + "first": true, + "optionnumber": 1, + "optionuniqid": "option1uniqid", + "selected": true + }, + { + "optionid": "option2", + "value": "value2", + "name": "Second option", + "description": "Second option description", + "icon": { + "extraclasses": "iconhelp", + "attributes": [ + {"name": "src", "value": "../../../pix/help.svg"}, + {"name": "alt", "value": "Help icon"} + ] + }, + "hasicon": true, + "optionnumber": 2, + "optionuniqid": "option2uniqid" + }, + { + "optionid": "option3", + "value": "value3", + "name": "Third option", + "description": "Third option description", + "icon": { + "extraclasses": "iconhelp", + "attributes": [ + {"name": "src", "value": "../../../pix/help.svg"}, + {"name": "alt", "value": "Help icon"} + ] + }, + "hasicon": true, + "disabled": true, + "optionnumber": 3, + "optionuniqid": "option3uniqid" + } + ] + }, + "extras" : [ + { + "attribute" : "data-example", + "value" : "stickyfooter" + } + ], + "buttonclasses" : "extraclasses" + } +}} +{{< core/local/dropdown/dialog }} + {{$ dialogcontent }} + {{#dialogcontent}} +
{{{dialogcontent}}}
+ {{/dialogcontent}} + {{#choices}} +
+ {{#options}} +
+ {{#icon}} +
+ {{>core/pix_icon}} +
+ {{/icon}} +
+ {{#selected}} + {{#pix}} i/checkedcircle, core, {{#str}} selected, form {{/str}} {{/pix}} + {{/selected}} + {{^selected}} + {{#pix}} i/uncheckedcircle{{/pix}} + {{/selected}} +
+
+ + {{name}} + + {{#description}} +
+ {{{description}}} +
+ {{/description}} +
+
+ {{/options}} +
+ {{/choices}} + {{/ dialogcontent }} +{{/ core/local/dropdown/dialog }} diff --git a/theme/boost/scss/moodle/core.scss b/theme/boost/scss/moodle/core.scss index 114b347eb88..dd3cf2a9afd 100644 --- a/theme/boost/scss/moodle/core.scss +++ b/theme/boost/scss/moodle/core.scss @@ -2624,6 +2624,25 @@ input[disabled] { visibility: hidden; } +// Any dialog (modal or dropdown) forced max-widths limits. +.dialog-big { + max-width: $modal-md; +} + +.dialog-small { + max-width: $modal-sm; +} + +@include media-breakpoint-up(sm) { + .dialog-big { + width: $modal-md; + } + + .dialog-small { + width: $modal-sm; + } +} + // Emoji picker. $picker-width: 350px !default; $picker-width-xs: 320px !default; diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index 54c3f2c7a56..ce069538a5a 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -25432,6 +25432,22 @@ input[disabled] { visibility: hidden; } +.dialog-big { + max-width: 500px; +} + +.dialog-small { + max-width: 300px; +} + +@media (min-width: 576px) { + .dialog-big { + width: 500px; + } + .dialog-small { + width: 300px; + } +} .emoji-picker { width: 350px; height: 400px; diff --git a/theme/classic/style/moodle.css b/theme/classic/style/moodle.css index 2c8445d995a..89c87d338c9 100644 --- a/theme/classic/style/moodle.css +++ b/theme/classic/style/moodle.css @@ -25432,6 +25432,22 @@ input[disabled] { visibility: hidden; } +.dialog-big { + max-width: 500px; +} + +.dialog-small { + max-width: 300px; +} + +@media (min-width: 576px) { + .dialog-big { + width: 500px; + } + .dialog-small { + width: 300px; + } +} .emoji-picker { width: 350px; height: 400px;