mirror of
https://github.com/moodle/moodle.git
synced 2025-04-14 04:52:36 +02:00
Merge branch 'MDL-77105-master-4' of https://github.com/junpataleta/moodle
This commit is contained in:
commit
efac6d72cf
@ -51,17 +51,18 @@ class recentlyaccesseditems_item_exporter extends \core\external\exporter {
|
||||
protected function get_other_values(renderer_base $output) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/modinfolib.php');
|
||||
|
||||
$iconurl = get_fast_modinfo($this->data->courseid)->cms[$this->data->cmid]->get_icon_url();
|
||||
$iconclass = $iconurl->get_param('filtericon') ? '' : 'nofilter';
|
||||
return array(
|
||||
'viewurl' => (new moodle_url('/mod/'.$this->data->modname.'/view.php',
|
||||
array('id' => $this->data->cmid)))->out(false),
|
||||
'courseviewurl' => (new moodle_url('/course/view.php', array('id' => $this->data->courseid)))->out(false),
|
||||
'icon' => \html_writer::img(
|
||||
get_fast_modinfo($this->data->courseid)->cms[$this->data->cmid]->get_icon_url(),
|
||||
$iconurl,
|
||||
get_string('pluginname', $this->data->modname),
|
||||
['title' => get_string('pluginname', $this->data->modname), 'class' => 'icon']
|
||||
['title' => get_string('pluginname', $this->data->modname), 'class' => "icon $iconclass"]
|
||||
),
|
||||
'purpose' => plugin_supports('mod', $this->data->modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER)
|
||||
'purpose' => plugin_supports('mod', $this->data->modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@
|
||||
<div class="activityiconcontainer small {{purpose}} courseicon align-self-top align-self-center mx-3 mb-1 mb-sm-0 text-nowrap">
|
||||
{{#icon}}
|
||||
{{#iconurl}}
|
||||
<img alt="{{alttext}}" title="{{alttext}}" src="{{{ iconurl }}}" class="icon ">
|
||||
<img alt="{{alttext}}" title="{{alttext}}" src="{{{ iconurl }}}" class="icon {{iconclass}}">
|
||||
{{/iconurl}}
|
||||
{{^iconurl}}
|
||||
{{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}}
|
||||
|
@ -62,12 +62,15 @@ class event_icon_exporter extends exporter {
|
||||
$isgroupevent = ($group && !empty($groupid));
|
||||
$isuserevent = ($user && !empty($userid));
|
||||
$iconurl = '';
|
||||
$iconclass = '';
|
||||
|
||||
if ($isactivityevent) {
|
||||
$key = 'monologo';
|
||||
$component = $coursemodule->get('modname');
|
||||
|
||||
$iconurl = get_fast_modinfo($courseid)->get_cm($coursemodule->get('id'))->get_icon_url()->out(false);
|
||||
$iconurl = get_fast_modinfo($courseid)->get_cm($coursemodule->get('id'))->get_icon_url();
|
||||
$iconclass = $iconurl->get_param('filtericon') ? '' : 'nofilter';
|
||||
$iconurl = $iconurl->out(false);
|
||||
if (get_string_manager()->string_exists($event->get_type(), $component)) {
|
||||
$alttext = get_string($event->get_type(), $component);
|
||||
} else {
|
||||
@ -121,6 +124,7 @@ class event_icon_exporter extends exporter {
|
||||
$data->component = $component;
|
||||
$data->alttext = $alttext;
|
||||
$data->iconurl = $iconurl;
|
||||
$data->iconclass = $iconclass;
|
||||
|
||||
parent::__construct($data, $related);
|
||||
}
|
||||
@ -136,6 +140,7 @@ class event_icon_exporter extends exporter {
|
||||
'component' => ['type' => PARAM_TEXT],
|
||||
'alttext' => ['type' => PARAM_TEXT],
|
||||
'iconurl' => ['type' => PARAM_TEXT],
|
||||
'iconclass' => ['type' => PARAM_TEXT],
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ namespace core_course\local\repository;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use core_component;
|
||||
use core_course\local\entity\content_item;
|
||||
use core_course\local\entity\lang_string_title;
|
||||
use core_course\local\entity\string_title;
|
||||
@ -195,12 +196,20 @@ class content_item_readonly_repository implements content_item_readonly_reposito
|
||||
$archetype = plugin_supports('mod', $mod->name, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
|
||||
$purpose = plugin_supports('mod', $mod->name, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER);
|
||||
|
||||
$icon = 'monologo';
|
||||
// Quick check for monologo icons.
|
||||
// Plugins that don't have monologo icons will be displayed as is and CSS filter will not be applied.
|
||||
$hasmonologoicons = core_component::has_monologo_icon('mod', $mod->name);
|
||||
$iconclass = '';
|
||||
if (!$hasmonologoicons) {
|
||||
$iconclass = 'nofilter';
|
||||
}
|
||||
$contentitem = new content_item(
|
||||
$mod->id,
|
||||
$mod->name,
|
||||
new lang_string_title("modulename", $mod->name),
|
||||
new \moodle_url('/course/mod.php', ['id' => $course->id, 'add' => $mod->name]),
|
||||
$OUTPUT->pix_icon('monologo', '', $mod->name, ['class' => 'icon activityicon']),
|
||||
$OUTPUT->pix_icon($icon, '', $mod->name, ['class' => "activityicon $iconclass"]),
|
||||
$help,
|
||||
$archetype,
|
||||
'mod_' . $mod->name,
|
||||
|
@ -102,9 +102,12 @@ class cmname implements named_templatable, renderable {
|
||||
return [];
|
||||
}
|
||||
|
||||
$iconurl = $mod->get_icon_url();
|
||||
$iconclass = $iconurl->get_param('filtericon') ? '' : 'nofilter';
|
||||
$data = [
|
||||
'url' => $mod->url,
|
||||
'icon' => $mod->get_icon_url(),
|
||||
'icon' => $iconurl,
|
||||
'iconclass' => $iconclass,
|
||||
'modname' => $mod->modname,
|
||||
'textclasses' => $displayoptions['textclasses'] ?? '',
|
||||
'purpose' => plugin_supports('mod', $mod->modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER),
|
||||
|
@ -25,6 +25,7 @@
|
||||
{
|
||||
"url": "#",
|
||||
"icon": "../../../pix/help.svg",
|
||||
"iconclass": "",
|
||||
"pluginname": "File",
|
||||
"textclasses": "",
|
||||
"purpose": "content",
|
||||
@ -47,7 +48,7 @@
|
||||
<div class="activity-instance d-flex flex-column">
|
||||
<div class="activitytitle media {{textclasses}} modtype_{{modname}} position-relative align-self-start">
|
||||
<div class="activityiconcontainer {{purpose}} courseicon align-self-start mr-3">
|
||||
<img src="{{{icon}}}" class="activityicon " alt="{{{modname}}} icon">
|
||||
<img src="{{{icon}}}" class="activityicon {{iconclass}}" alt="{{{modname}}} icon">
|
||||
</div>
|
||||
<div class="media-body align-self-center">
|
||||
{{#pluginname}}
|
||||
|
@ -1337,4 +1337,22 @@ $cache = '.var_export($cache, true).';
|
||||
public static function get_core_api_names(): array {
|
||||
return array_keys(self::get_core_apis());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the presence of monologo icons within a plugin.
|
||||
*
|
||||
* Only checks monologo icons in PNG and SVG formats as they are
|
||||
* formats that can have transparent background.
|
||||
*
|
||||
* @param string $plugintype The plugin type.
|
||||
* @param string $pluginname The plugin name.
|
||||
* @return bool True if the plugin has a monologo icon
|
||||
*/
|
||||
public static function has_monologo_icon(string $plugintype, string $pluginname): bool {
|
||||
$plugindir = core_component::get_plugin_directory($plugintype, $pluginname);
|
||||
if ($plugindir === null) {
|
||||
return false;
|
||||
}
|
||||
return file_exists("$plugindir/pix/monologo.svg") || file_exists("$plugindir/pix/monologo.png");
|
||||
}
|
||||
}
|
||||
|
@ -1763,7 +1763,15 @@ class cm_info implements IteratorAggregate {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param moodle_core_renderer $output Output render to use, or null for default (global)
|
||||
* Fetch the module's icon URL.
|
||||
*
|
||||
* This function fetches the course module instance's icon URL.
|
||||
* This method adds a `filtericon` parameter in the URL when rendering the monologo version of the course module icon or when
|
||||
* the plugin declares, via its `filtericon` custom data, that the icon needs to be filtered.
|
||||
* This additional information can be used by plugins when rendering the module icon to determine whether to apply
|
||||
* CSS filtering to the icon.
|
||||
*
|
||||
* @param core_renderer $output Output render to use, or null for default (global)
|
||||
* @return moodle_url Icon URL for a suitable icon to put beside this cm
|
||||
*/
|
||||
public function get_icon_url($output = null) {
|
||||
@ -1773,6 +1781,7 @@ class cm_info implements IteratorAggregate {
|
||||
$output = $OUTPUT;
|
||||
}
|
||||
|
||||
$ismonologo = false;
|
||||
if (!empty($this->iconurl)) {
|
||||
// Support modules setting their own, external, icon image.
|
||||
$icon = $this->iconurl;
|
||||
@ -1792,6 +1801,17 @@ class cm_info implements IteratorAggregate {
|
||||
}
|
||||
} else {
|
||||
$icon = $output->image_url('monologo', $this->modname);
|
||||
// Activity modules may only have an `icon` icon instead of a `monologo` icon.
|
||||
// So we need to determine if the module really has a `monologo` icon.
|
||||
$ismonologo = core_component::has_monologo_icon('mod', $this->modname);
|
||||
}
|
||||
|
||||
// Determine whether the icon will be filtered in the CSS.
|
||||
// This can be controlled by the module by declaring a 'filtericon' custom data.
|
||||
// If the 'filtericon' custom data is not set, icon filtering will be determined whether the module has a `monologo` icon.
|
||||
$filtericon = $this->customdata['filtericon'] ?? $ismonologo;
|
||||
if ($filtericon) {
|
||||
$icon->param('filtericon', 1);
|
||||
}
|
||||
return $icon;
|
||||
}
|
||||
|
@ -931,4 +931,19 @@ class component_test extends advanced_testcase {
|
||||
$this->assertLessThanOrEqual($attributes->allowedlevel2, $attributes->allowedspread, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for monologo icons check in plugins.
|
||||
*
|
||||
* @covers core_component::has_monologo_icon
|
||||
* @return void
|
||||
*/
|
||||
public function test_has_monologo_icon(): void {
|
||||
// The Forum activity plugin has monologo icons.
|
||||
$this->assertTrue(core_component::has_monologo_icon('mod', 'forum'));
|
||||
// The core H5P subsystem doesn't have monologo icons.
|
||||
$this->assertFalse(core_component::has_monologo_icon('core', 'h5p'));
|
||||
// The function will return false for a non-existent component.
|
||||
$this->assertFalse(core_component::has_monologo_icon('randomcomponent', 'h5p'));
|
||||
}
|
||||
}
|
||||
|
@ -103,6 +103,17 @@ information provided here is intended especially for developers.
|
||||
Please use the new core_grades_get_enrolled_users_for_selector external function instead.
|
||||
* The external function core_grades_get_groups_for_search_widget is now deprecated.
|
||||
Please use the new core_grades_get_groups_for_selector external function instead.
|
||||
* New \core_component::has_monologo_icon() that determines whether a plugin has monologo icons. This can be used to
|
||||
determine whether to apply CSS filtering to the plugin's icon when rendering it.
|
||||
* \cm_info::get_icon_url() resolves the icon's file type and adds a `filtericon` parameter in the URL when rendering the monologo
|
||||
version of the course module icon or when the plugin declares, via its `filtericon` custom data, that the icon needs to be
|
||||
filtered. This additional information can be used by plugins when rendering the module icon to determine whether to apply
|
||||
CSS filtering to the icon.
|
||||
* Activity plugins displaying activity module icons using \cm_info::get_icon_url() can declare the `filtericon` custom data in their
|
||||
`get_coursemodule_info()` callback. If set, this will be used by \cm_info::get_icon_url() to set the icon URL's `filtericon`
|
||||
parameter. This information can be used by the plugins when enclosing the icons in `.activityiconcontainer .icon` or
|
||||
`.activityiconcontainer .activityicon` containers to determine whether CSS filtering should be applied to the icon. If the icon
|
||||
needs to be rendered as is and not whitened out, the `.nofilter` CSS class needs to be applied to the icon.
|
||||
|
||||
=== 4.1 ===
|
||||
|
||||
|
@ -2387,7 +2387,15 @@ function lti_get_configured_types($courseid, $sectionreturn = 0) {
|
||||
$type->help = clean_param($trimmeddescription, PARAM_NOTAGS);
|
||||
$type->helplink = get_string('modulename_shortcut_link', 'lti');
|
||||
}
|
||||
$type->icon = html_writer::empty_tag('img', ['src' => get_tool_type_icon_url($ltitype), 'alt' => '', 'class' => 'icon']);
|
||||
|
||||
$iconurl = get_tool_type_icon_url($ltitype);
|
||||
$iconclass = '';
|
||||
if ($iconurl !== $OUTPUT->image_url('monologo', 'lti')->out()) {
|
||||
// Do not filter the icon if it is not the default LTI activity icon.
|
||||
$iconclass = 'nofilter';
|
||||
}
|
||||
$type->icon = html_writer::empty_tag('img', ['src' => $iconurl, 'alt' => '', 'class' => "icon $iconclass"]);
|
||||
|
||||
$type->link = new moodle_url('/course/modedit.php', array('add' => 'lti', 'return' => 0, 'course' => $courseid,
|
||||
'sr' => $sectionreturn, 'typeid' => $ltitype->id));
|
||||
$types[] = $type;
|
||||
|
@ -245,6 +245,8 @@ function url_get_coursemodule_info($coursemodule) {
|
||||
}
|
||||
|
||||
$info->customdata['display'] = $display;
|
||||
// The icon will be filtered if it will be the default module icon.
|
||||
$info->customdata['filtericon'] = empty($info->icon);
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
@ -160,8 +160,13 @@ class core_renderer extends \core_renderer {
|
||||
$heading = format_string($this->page->course->fullname, true, ['context' => $context]);
|
||||
} else {
|
||||
$heading = $this->page->cm->get_formatted_name();
|
||||
$imagedata = html_writer::img($this->page->cm->get_icon_url()->out(false), '',
|
||||
['class' => 'icon activityicon', 'aria-hidden' => 'true']);
|
||||
$iconurl = $this->page->cm->get_icon_url();
|
||||
$iconclass = $iconurl->get_param('filtericon') ? '' : 'nofilter';
|
||||
$iconattrs = [
|
||||
'class' => "icon activityicon $iconclass",
|
||||
'aria-hidden' => 'true'
|
||||
];
|
||||
$imagedata = html_writer::img($iconurl->out(false), '', $iconattrs);
|
||||
$purposeclass = plugin_supports('mod', $this->page->activityname, FEATURE_MOD_PURPOSE);
|
||||
$purposeclass .= ' activityiconcontainer';
|
||||
$purposeclass .= ' modicon_' . $this->page->activityname;
|
||||
|
@ -157,7 +157,9 @@ $iconsizes: map-merge((
|
||||
background-color: $value;
|
||||
.activityicon,
|
||||
.icon {
|
||||
filter: brightness(0) invert(1);
|
||||
&:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26066,48 +26066,48 @@ blockquote {
|
||||
.activityiconcontainer.administration {
|
||||
background-color: #5d63f6;
|
||||
}
|
||||
.activityiconcontainer.administration .activityicon,
|
||||
.activityiconcontainer.administration .icon {
|
||||
.activityiconcontainer.administration .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.administration .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.assessment {
|
||||
background-color: #eb66a2;
|
||||
}
|
||||
.activityiconcontainer.assessment .activityicon,
|
||||
.activityiconcontainer.assessment .icon {
|
||||
.activityiconcontainer.assessment .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.assessment .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.collaboration {
|
||||
background-color: #f7634d;
|
||||
}
|
||||
.activityiconcontainer.collaboration .activityicon,
|
||||
.activityiconcontainer.collaboration .icon {
|
||||
.activityiconcontainer.collaboration .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.collaboration .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.communication {
|
||||
background-color: #11a676;
|
||||
}
|
||||
.activityiconcontainer.communication .activityicon,
|
||||
.activityiconcontainer.communication .icon {
|
||||
.activityiconcontainer.communication .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.communication .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.content {
|
||||
background-color: #399be2;
|
||||
}
|
||||
.activityiconcontainer.content .activityicon,
|
||||
.activityiconcontainer.content .icon {
|
||||
.activityiconcontainer.content .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.content .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.interface {
|
||||
background-color: #a378ff;
|
||||
}
|
||||
.activityiconcontainer.interface .activityicon,
|
||||
.activityiconcontainer.interface .icon {
|
||||
.activityiconcontainer.interface .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.interface .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
|
@ -26066,48 +26066,48 @@ blockquote {
|
||||
.activityiconcontainer.administration {
|
||||
background-color: #5d63f6;
|
||||
}
|
||||
.activityiconcontainer.administration .activityicon,
|
||||
.activityiconcontainer.administration .icon {
|
||||
.activityiconcontainer.administration .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.administration .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.assessment {
|
||||
background-color: #eb66a2;
|
||||
}
|
||||
.activityiconcontainer.assessment .activityicon,
|
||||
.activityiconcontainer.assessment .icon {
|
||||
.activityiconcontainer.assessment .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.assessment .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.collaboration {
|
||||
background-color: #f7634d;
|
||||
}
|
||||
.activityiconcontainer.collaboration .activityicon,
|
||||
.activityiconcontainer.collaboration .icon {
|
||||
.activityiconcontainer.collaboration .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.collaboration .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.communication {
|
||||
background-color: #11a676;
|
||||
}
|
||||
.activityiconcontainer.communication .activityicon,
|
||||
.activityiconcontainer.communication .icon {
|
||||
.activityiconcontainer.communication .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.communication .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.content {
|
||||
background-color: #399be2;
|
||||
}
|
||||
.activityiconcontainer.content .activityicon,
|
||||
.activityiconcontainer.content .icon {
|
||||
.activityiconcontainer.content .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.content .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
.activityiconcontainer.interface {
|
||||
background-color: #a378ff;
|
||||
}
|
||||
.activityiconcontainer.interface .activityicon,
|
||||
.activityiconcontainer.interface .icon {
|
||||
.activityiconcontainer.interface .activityicon:not(.nofilter),
|
||||
.activityiconcontainer.interface .icon:not(.nofilter) {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user