From 3c7a883503b5584bad6865c17d5053dca492197f Mon Sep 17 00:00:00 2001 From: Alexander Bias Date: Fri, 12 Jul 2024 13:45:05 +0200 Subject: [PATCH] Upgrade: Adopt changes for coloring the activity icons when modifying the activity purpose. --- CHANGES.md | 1 + README.md | 26 ++++ lang/en/theme_boost_union.php | 23 ++++ locallib.php | 65 +++++++--- settings.php | 64 +++++++++ .../core_calendar/upcoming_mini.mustache | 121 ++++++++++++++++++ .../upcoming_mini.mustache.upstream | 115 +++++++++++++++++ ...nion_looksettings_activitybranding.feature | 22 ++-- ...me_boost_union_looksettings_blocks.feature | 53 ++++++++ 9 files changed, 464 insertions(+), 26 deletions(-) create mode 100644 templates/core_calendar/upcoming_mini.mustache create mode 100644 templates/core_calendar/upcoming_mini.mustache.upstream create mode 100644 tests/behat/theme_boost_union_looksettings_blocks.feature diff --git a/CHANGES.md b/CHANGES.md index 166dae6400e..913c3e028e4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Changes ### Unreleased +* 2024-07-12 - Upgrade: Adopt changes for coloring the activity icons when modifying the activity purpose. * 2024-07-12 - Upgrade: Adopt new activity purpose "Interactive content" when coloring activity icons, resolves #611. * 2024-07-07 - Upgrade: Adopt changes for coloring the activity icons, moving from background-colors to CSS filters, resolves #631. * 2024-07-04 - Upgrade: Fix Behat tests which broke due to the introduction of section pages in Moodle core. diff --git a/README.md b/README.md index 5ddef03384c..a655d92d308 100644 --- a/README.md +++ b/README.md @@ -225,6 +225,32 @@ With this setting, you can control whether the course image is visible inside th With this setting, you can control whether the course completion progress is visible inside the course overview block or not. +#### Tab "Blocks" + +##### Timeline block + +###### Tint timeline activity icons + +With this setting, you can tint the activity icons in the timeline block based on the activity purposes. By default, Moodle core displays them just as black icons. + +##### Upcoming events block + +###### Tint upcoming events activity icons + +With this setting, you can tint the activity icons in the upcoming events block based on the activity purposes. By default, Moodle core displays them just as black icons. + +##### Recently accessed items block + +###### Tint recently accessed items activity icons + +With this setting, you can tint the activity icons in the recently accessed items block based on the activity purposes. By default, Moodle core displays them just as black icons. + +##### Activities block + +###### Tint activities activity icons + +With this setting, you can tint the activity icons in the activities block based on the activity purposes. By default, Moodle core displays them just as black icons. + #### Tab "Course" ##### Course Header diff --git a/lang/en/theme_boost_union.php b/lang/en/theme_boost_union.php index 244f455999d..809bad3d471 100644 --- a/lang/en/theme_boost_union.php +++ b/lang/en/theme_boost_union.php @@ -311,6 +311,29 @@ $string['courseoverviewshowprogresssetting'] = 'Show course completion progress'; $string['courseoverviewshowprogresssetting_desc'] = 'With this setting, you can control whether the course completion progress is visible inside the course overview block or not.'; +// Settings: Blocks tab. +// The string for this tab is the same as on the 'Feel' page. +// ... Section: Timeline block. +$string['timelineheading'] = 'Timeline block'; +// Setting: Tint activity icons in the timeline block. +$string['timelinetintenabled'] = 'Tint timeline activity icons'; +$string['timelinetintenabled_desc'] = 'With this setting, you can tint the activity icons in the timeline block based on the activity purposes. By default, Moodle core displays them just as black icons.'; +// ... Section: Upcoming events block. +$string['upcomingeventsheading'] = 'Upcoming events block'; +// Setting: Tint activity icons in the upcoming events block. +$string['upcomingeventstintenabled'] = 'Tint upcoming events activity icons'; +$string['upcomingeventstintenabled_desc'] = 'With this setting, you can tint the activity icons in the upcoming events block based on the activity purposes. By default, Moodle core displays them just as black icons.'; +// ... Section: Recently accessed items block. +$string['recentlyaccesseditemsheading'] = 'Recently accessed items block'; +// Setting: Tint activity icons in the recently accessed items block. +$string['recentlyaccesseditemstintenabled'] = 'Tint recently accessed items activity icons'; +$string['recentlyaccesseditemstintenabled_desc'] = 'With this setting, you can tint the activity icons in the recently accessed items block based on the activity purposes. By default, Moodle core displays them just as black icons.'; +// ... Section: Activities block. +$string['activitiesheading'] = 'Activities block'; +// Setting: Tint activity icons in the activities block. +$string['activitiestintenabled'] = 'Tint activities activity icons'; +$string['activitiestintenabled_desc'] = 'With this setting, you can tint the activity icons in the activities block based on the activity purposes. By default, Moodle core displays them just as black icons.'; + // Settings: Course tab. $string['coursetab'] = 'Course'; // ... Section: Course header. diff --git a/locallib.php b/locallib.php index 69a3132ab69..e6e9a366043 100644 --- a/locallib.php +++ b/locallib.php @@ -1376,37 +1376,68 @@ function theme_boost_union_get_scss_for_activity_icon_purpose($theme) { foreach ($installedactivities as $modname => $modinfo) { // Get default purpose of activity module. $defaultpurpose = plugin_supports('mod', $modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER); + // If the plugin does not have any default purpose. if (!$defaultpurpose) { // Fallback to "other" purpose. $defaultpurpose = MOD_PURPOSE_OTHER; } + + // Compose selectors for blocks. + $blocksscss = []; + // If the admin wanted us to tint the timeline block as well. + if (get_config('theme_boost_union', 'timelinetintenabled') == THEME_BOOST_UNION_SETTING_SELECT_YES) { + $blocksscss[] = '.block_timeline .theme-boost-union-mod_'.$modname.'.activityiconcontainer img'; + } + // If the admin wanted us to tint the upcoming events block as well. + if (get_config('theme_boost_union', 'upcomingeventstintenabled') == THEME_BOOST_UNION_SETTING_SELECT_YES) { + $blocksscss[] = '.block_calendar_upcoming .theme-boost-union-mod_'.$modname.'.activityiconcontainer img'; + } + // If the admin wanted us to tint the recently accessed items block as well. + if (get_config('theme_boost_union', 'recentlyaccesseditemstintenabled') == THEME_BOOST_UNION_SETTING_SELECT_YES) { + $blocksscss[] = '.block_recentlyaccesseditems .theme-boost-union-'.$modname.'.activityiconcontainer img'; + } + // If the admin wanted us to tint the activities block as well. + if (get_config('theme_boost_union', 'activitiestintenabled') == THEME_BOOST_UNION_SETTING_SELECT_YES) { + $blocksscss[] = '.block_activity_modules .content .icon[title="'.$modinfo.'"]'; + } + $blocksscss = implode(', ', $blocksscss); + // If the activity purpose setting is set and differs from the activity's default purpose. $activitypurpose = get_config('theme_boost_union', 'activitypurpose'.$modname); if ($activitypurpose && $activitypurpose != $defaultpurpose) { // Add CSS to modify the activity purpose color in the activity chooser and the activity icon. - $scss .= '.activity.modtype_'.$modname.' .activityiconcontainer.courseicon,'; - $scss .= '.modchoosercontainer .modicon_'.$modname.'.activityiconcontainer,'; - $scss .= '#page-header .modicon_'.$modname.'.activityiconcontainer,'; - $scss .= '.block_recentlyaccesseditems .theme-boost-union-'.$modname.'.activityiconcontainer,'; - $scss .= '.block_timeline .theme-boost-union-mod_'.$modname.'.activityiconcontainer {'; - // If the purpose is now different than 'other', change the background color to the new color. + $scss .= '.activity.modtype_'.$modname.' .activityiconcontainer.courseicon img,'; + $scss .= '.modchoosercontainer .modicon_'.$modname.'.activityiconcontainer img,'; + $scss .= '#page-header .modicon_'.$modname.'.activityiconcontainer img'; + // Add CSS for the configured blocks. + if (strlen($blocksscss) > 0) { + $scss .= ', '.$blocksscss; + } + $scss .= ' {'; + // If the purpose is now different than 'other', change the filter to the new color. if ($activitypurpose != MOD_PURPOSE_OTHER) { - $scss .= 'background-color: var(--activity' . $activitypurpose . ') !important;'; + $scss .= 'filter: var(--activity' . $activitypurpose . ') !important;'; - // Otherwise, the background color is set to light grey (as there is no '--activityother' variable). + // Otherwise, the filter is removed (as there is no '--activityother' variable). } else { - $scss .= 'background-color: $light !important;'; - } - // If the default purpose originally was 'other' and now is overridden, make the icon white. - if ($defaultpurpose == MOD_PURPOSE_OTHER) { - $scss .= '.activityicon, .icon { filter: brightness(0) invert(1); }'; - } - // If the default purpose was not 'other' and now it is, make the icon black. - if ($activitypurpose == MOD_PURPOSE_OTHER) { - $scss .= '.activityicon, .icon { filter: none; }'; + $scss .= 'filter: none !important;'; } $scss .= '}'; + + // Otherwise, if the purpose is unchanged. + } else { + // Add CSS for the configured blocks. + if (strlen($blocksscss) > 0) { + $scss .= $blocksscss.'{ '; + + // If the purpose is now different than 'other', set the filter to tint the icon. + if ($activitypurpose != MOD_PURPOSE_OTHER) { + $scss .= 'filter: var(--activity' . $defaultpurpose . ') !important;'; + } + + $scss .= '}'; + } } } return $scss; diff --git a/settings.php b/settings.php index 914d8213b83..beb6d5214ad 100644 --- a/settings.php +++ b/settings.php @@ -851,6 +851,70 @@ $page->add($tab); + // Create Blocks tab. + $tab = new admin_settingpage('theme_boost_union_look_blocks', + get_string('blockstab', 'theme_boost_union', null, true)); + + // Create Timeline block heading. + $name = 'theme_boost_union/timelineheading'; + $title = get_string('timelineheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Tint activity icons in the timeline block. + $name = 'theme_boost_union/timelinetintenabled'; + $title = get_string('timelinetintenabled', 'theme_boost_union', null, true); + $description = get_string('timelinetintenabled_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, $yesnooption); + $setting->set_updatedcallback('theme_reset_all_caches'); + $tab->add($setting); + + // Create Upcoming events block heading. + $name = 'theme_boost_union/upcomingeventsheading'; + $title = get_string('upcomingeventsheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Tint activity icons in the upcoming events block. + $name = 'theme_boost_union/upcomingeventstintenabled'; + $title = get_string('upcomingeventstintenabled', 'theme_boost_union', null, true); + $description = get_string('upcomingeventstintenabled_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, $yesnooption); + $setting->set_updatedcallback('theme_reset_all_caches'); + $tab->add($setting); + + // Create Recently accessed items block heading. + $name = 'theme_boost_union/recentlyaccesseditemsheading'; + $title = get_string('recentlyaccesseditemsheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Tint activity icons in the recently accessed items block. + $name = 'theme_boost_union/recentlyaccesseditemstintenabled'; + $title = get_string('recentlyaccesseditemstintenabled', 'theme_boost_union', null, true); + $description = get_string('recentlyaccesseditemstintenabled_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, $yesnooption); + $setting->set_updatedcallback('theme_reset_all_caches'); + $tab->add($setting); + + // Create Activities block heading. + $name = 'theme_boost_union/activitiesheading'; + $title = get_string('activitiesheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Tint activity icons in the activities block. + $name = 'theme_boost_union/activitiestintenabled'; + $title = get_string('activitiestintenabled', 'theme_boost_union', null, true); + $description = get_string('activitiestintenabled_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, $yesnooption); + $setting->set_updatedcallback('theme_reset_all_caches'); + $tab->add($setting); + + // Add tab to settings page. + $page->add($tab); + + // Create course tab. $tab = new admin_settingpage('theme_boost_union_look_course', get_string('coursetab', 'theme_boost_union', null, true)); diff --git a/templates/core_calendar/upcoming_mini.mustache b/templates/core_calendar/upcoming_mini.mustache new file mode 100644 index 00000000000..7dc7de05c4b --- /dev/null +++ b/templates/core_calendar/upcoming_mini.mustache @@ -0,0 +1,121 @@ +{{! + 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_calendar/upcoming_mini + + Calendar upcoming view for blocks. + + The purpose of this template is to render the upcoming view for blocks. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Example context (json): + { + } +}} +{{! + This template is a modified version of core_calendar/upcoming_mini + + Modifications compared to the original template: + * Added component placeholder to the activityiconcontainer element to support overwriting of activity purposes. +}} +
+ {{> core/overlay_loading}} + {{#events}} + +
+ {{#icon}} + {{#iconurl}} + {{alttext}} + {{/iconurl}} + {{^iconurl}} + {{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}} + {{/iconurl}} + {{/icon}} +
+
+
+ {{{name}}} +
+
{{{formattedtime}}}
+
+
+ {{/events}} + {{^events}} + {{#str}}noupcomingevents, calendar{{/str}} + {{/events}} + +{{#js}} +require([ + 'jquery', + 'core_calendar/selectors', + 'core_calendar/events', +], function( + $, + CalendarSelectors, + CalendarEvents +) { + var root = $('#month-upcoming-mini-{{uniqid}}'); + + $('body').on(CalendarEvents.filterChanged, function(e, data) { + M.util.js_pending("month-upcoming-mini-{{uniqid}}-filterChanged"); + + // A filter value has been changed. + // Find all matching cells in the popover data, and hide them. + var target = $("#month-upcoming-mini-{{uniqid}}").find(CalendarSelectors.eventType[data.type]); + + var transitionPromise = $.Deferred(); + if (data.hidden) { + transitionPromise.then(function() { + return target.slideUp('fast').promise(); + }); + } else { + transitionPromise.then(function() { + return target.slideDown('fast').promise(); + }); + } + + transitionPromise.then(function() { + M.util.js_complete("month-upcoming-mini-{{uniqid}}-filterChanged"); + + return; + }); + + transitionPromise.resolve(); + }); +}); +{{/js}} diff --git a/templates/core_calendar/upcoming_mini.mustache.upstream b/templates/core_calendar/upcoming_mini.mustache.upstream new file mode 100644 index 00000000000..4e34b7f47aa --- /dev/null +++ b/templates/core_calendar/upcoming_mini.mustache.upstream @@ -0,0 +1,115 @@ +{{! + 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_calendar/upcoming_mini + + Calendar upcoming view for blocks. + + The purpose of this template is to render the upcoming view for blocks. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Example context (json): + { + } +}} +
+ {{> core/overlay_loading}} + {{#events}} + +
+ {{#icon}} + {{#iconurl}} + {{alttext}} + {{/iconurl}} + {{^iconurl}} + {{#pix}} {{key}}, {{component}}, {{alttext}} {{/pix}} + {{/iconurl}} + {{/icon}} +
+
+
+ {{{name}}} +
+
{{{formattedtime}}}
+
+
+ {{/events}} + {{^events}} + {{#str}}noupcomingevents, calendar{{/str}} + {{/events}} + +{{#js}} +require([ + 'jquery', + 'core_calendar/selectors', + 'core_calendar/events', +], function( + $, + CalendarSelectors, + CalendarEvents +) { + var root = $('#month-upcoming-mini-{{uniqid}}'); + + $('body').on(CalendarEvents.filterChanged, function(e, data) { + M.util.js_pending("month-upcoming-mini-{{uniqid}}-filterChanged"); + + // A filter value has been changed. + // Find all matching cells in the popover data, and hide them. + var target = $("#month-upcoming-mini-{{uniqid}}").find(CalendarSelectors.eventType[data.type]); + + var transitionPromise = $.Deferred(); + if (data.hidden) { + transitionPromise.then(function() { + return target.slideUp('fast').promise(); + }); + } else { + transitionPromise.then(function() { + return target.slideDown('fast').promise(); + }); + } + + transitionPromise.then(function() { + M.util.js_complete("month-upcoming-mini-{{uniqid}}-filterChanged"); + + return; + }); + + transitionPromise.resolve(); + }); +}); +{{/js}} diff --git a/tests/behat/theme_boost_union_looksettings_activitybranding.feature b/tests/behat/theme_boost_union_looksettings_activitybranding.feature index 2c82eec8691..e34748a5609 100644 --- a/tests/behat/theme_boost_union_looksettings_activitybranding.feature +++ b/tests/behat/theme_boost_union_looksettings_activitybranding.feature @@ -44,20 +44,24 @@ Feature: Configuring the theme_boost_union plugin for the "Activity branding" ta And I select "" from the "" singleselect And I press "Save changes" And Behat debugging is enabled - And I am on "Course 1" course homepage + When I am on "Course 1" course homepage And I turn editing mode on - When I click on "Add an activity or resource" "button" in the "New section" "section" - # We just test if the color in the activity chooser was changed. - # Testing all other locations where the activity icons are shown as well and where Boost Union had to modify - # the color individually as well would be an overhead which does not really make sense here. - Then DOM element ".chooser-container .activityiconcontainer.modicon_" should have computed style "background-color" "" + And I add a activity to course "Course 1" section "0" and I fill the form with: + | | Test name | + Then DOM element ".activity.modtype_ .activityiconcontainer.courseicon img" should have computed style "filter" "" + And I click on "Add an activity or resource" "button" in the "New section" "section" + Then DOM element ".chooser-container .activityiconcontainer.modicon_ img" should have computed style "filter" "" + And I am on the "Test name" " activity" page + Then DOM element "#page-header .modicon_.activityiconcontainer img" should have computed style "filter" "" # We do not want to burn too much CPU time by testing all plugins. We just test two plugins which is fine as all plugins are handled with the same PHP code. + # In addition to that, we test the 'other purpose' which is special. # These examples will work until Moodle core changes the default colors of the module purpose types. Examples: - | modname | purpose | mod | colorrgb | - | Assignment | Collaboration | assign | rgb(247, 99, 77) | - | Book | Communication | book | rgb(17, 166, 118) | + | modname | titlesetting | purpose | mod | filter | + | Assignment | Assignment name | Collaboration | assign | invert(0.25) sepia(0.54) saturate(62.26) hue-rotate(245deg) brightness(1) contrast(1.02) | + | Book | Name | Communication | book | invert(0.48) sepia(0.74) saturate(48.87) hue-rotate(11deg) brightness(1.02) contrast(1.01) | + | Assignment | Assignment name | Other | assign | none | @javascript @_file_upload Scenario Outline: Setting: Custom icons files - Upload custom icons files diff --git a/tests/behat/theme_boost_union_looksettings_blocks.feature b/tests/behat/theme_boost_union_looksettings_blocks.feature new file mode 100644 index 00000000000..93f72b88863 --- /dev/null +++ b/tests/behat/theme_boost_union_looksettings_blocks.feature @@ -0,0 +1,53 @@ +@theme @theme_boost_union @theme_boost_union_looksettings @theme_boost_union_looksettings_blocks +Feature: Configuring the theme_boost_union plugin for the "Blocks" tab on the "Look" page + In order to use the features + As admin + I need to be able to configure the theme Boost Union plugin + + @javascript + Scenario Outline: Setting: Tint timeline / upcoming events / recently accessed items / activities activity icons - Enable the settings + Given the following config values are set as admin: + | config | value | plugin | + | timelinetintenabled | | theme_boost_union | + | upcomingeventstintenabled | | theme_boost_union | + | recentlyaccesseditemstintenabled | | theme_boost_union | + | activitiestintenabled | | theme_boost_union | + And the following "courses" exist: + | fullname | shortname | + | Course 1 | C1 | + And the following "activities" exist: + | activity | course | idnumber | name | intro | timeopen | duedate | + | assign | C1 | assign1 | Test assign | Test assign description | ##1 month ago## | ##tomorrow## | + And the following "course enrolments" exist: + | user | course | role | + | admin | C1 | student | + And the following "blocks" exist: + | blockname | contextlevel | reference | pagetypepattern | defaultregion | + | timeline | System | 1 | my-index | content | + | calendar_upcoming | System | 1 | my-index | content | + | recentlyaccesseditems | System | 1 | my-index | content | + | activity_modules | Course | C1 | course-view-* | side-pre | + And I log in as "admin" + And Behat debugging is disabled + And I navigate to "Appearance > Boost Union > Look" in site administration + And I click on "Activity branding" "link" in the "#adminsettings .nav-tabs" "css_element" + And I select "Collaboration" from the "Assignment" singleselect + And I press "Save changes" + And Behat debugging is enabled + And I am on "Course 1" course homepage + # Visiting the activity is necessar to fill the recently accessed items block. + And I am on the "Test assign" "assign activity" page + And I follow "Dashboard" + Then DOM element ".block_timeline .theme-boost-union-mod_assign.activityiconcontainer img" have computed style "filter" "invert(0.25) sepia(0.54) saturate(62.26) hue-rotate(245deg) brightness(1) contrast(1.02)" + And DOM element ".block_calendar_upcoming .theme-boost-union-mod_assign.activityiconcontainer img" have computed style "filter" "invert(0.25) sepia(0.54) saturate(62.26) hue-rotate(245deg) brightness(1) contrast(1.02)" + And DOM element ".block_recentlyaccesseditems .theme-boost-union-assign.activityiconcontainer img" have computed style "filter" "invert(0.25) sepia(0.54) saturate(62.26) hue-rotate(245deg) brightness(1) contrast(1.02)" + And I am on "Course 1" course homepage + Then DOM element ".block_activity_modules .content .icon[title=\'Assignment\']" have computed style "filter" "invert(0.25) sepia(0.54) saturate(62.26) hue-rotate(245deg) brightness(1) contrast(1.02)" + + Examples: + | tinttl | tintrc | tintue | tintac | shouldornottl | shouldornotrc | shouldornotue | shouldornotac | + | no | no | no | no | should not | should not | should not | should not | + | yes | no | no | no | should | should not | should not | should not | + | no | yes | no | no | should not | should | should not | should not | + | no | no | yes | no | should not | should not | should | should not | + | no | no | no | yes | should not | should not | should not | should |