From fdbd17743d755ac331a6a7f978d5bbe52762ed11 Mon Sep 17 00:00:00 2001 From: Katalin Lukacs Toth Date: Wed, 22 May 2024 15:53:17 +0200 Subject: [PATCH] Improvement: Implement accessibility statement and feedback mechanism, resolves #567. Co-authored-by: Katalin Lukacs Toth --- CHANGES.md | 1 + README.md | 14 +- amd/build/accessibilitysupportform.min.js | 12 ++ amd/build/accessibilitysupportform.min.js.map | 1 + amd/build/backtotopbutton.min.js | 2 +- amd/build/backtotopbutton.min.js.map | 2 +- amd/src/accessibilitysupportform.js | 64 ++++++ amd/src/backtotopbutton.js | 2 +- classes/form/accessibilitysupport_form.php | 169 +++++++++++++++ ...e_standard_top_of_body_html_generation.php | 49 +++++ db/hooks.php | 5 + lang/en/theme_boost_union.php | 71 +++++++ layout/columns2.php | 3 + layout/drawers.php | 3 + layout/includes/accessibilitypages.php | 75 +++++++ layout/includes/footer.php | 14 ++ layout/login.php | 3 + lib.php | 17 ++ locallib.php | 72 +++++++ pages/accessibility.php | 76 +++++++ pages/accessibilitysupport.php | 160 ++++++++++++++ scss/boost_union/post.scss | 86 ++++++-- settings.php | 166 +++++++++++++++ .../accessibility_support_email_body.mustache | 58 +++++ ...cessibility_support_not_available.mustache | 45 ++++ templates/footnote.mustache | 16 ++ templates/theme_boost/footer.mustache | 31 +++ .../behat_theme_boost_union_base_content.php | 18 ++ ...nion_contentsettings_accessibility.feature | 140 +++++++++++++ ..._union_contentsettings_staticpages.feature | 198 ++++++++++-------- 30 files changed, 1460 insertions(+), 113 deletions(-) create mode 100644 amd/build/accessibilitysupportform.min.js create mode 100644 amd/build/accessibilitysupportform.min.js.map create mode 100644 amd/src/accessibilitysupportform.js create mode 100644 classes/form/accessibilitysupport_form.php create mode 100644 classes/local/hook/output/before_standard_top_of_body_html_generation.php create mode 100644 layout/includes/accessibilitypages.php create mode 100644 pages/accessibility.php create mode 100644 pages/accessibilitysupport.php create mode 100644 templates/accessibility_support_email_body.mustache create mode 100644 templates/accessibility_support_not_available.mustache create mode 100644 tests/behat/theme_boost_union_contentsettings_accessibility.feature diff --git a/CHANGES.md b/CHANGES.md index 5a1f56a06df..b03c89014a6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -6,6 +6,7 @@ Changes ### Unreleased +* 2024-08-26 - Improvement: Implement accessibility statement and feedback mechanism, resolves #567. * 2024-08-24 - Upgrade: Update Bootstrap classes for Moodle 4.4. * 2024-08-11 - Updated Moodle Plugin CI to latest upstream recommendations * 2024-07-24 - Test: Fix broken Behat scenario 'Suppress 'Chat to course participants' link', resolves #696 diff --git a/README.md b/README.md index 0896f6b893a..eeb6272f746 100644 --- a/README.md +++ b/README.md @@ -559,6 +559,18 @@ With these settings, you can add rich text content which will be shown on a gene With these settings, you can add rich text content which will be shown on a generic page 3. +#### Tab "Accessibility" + +In this tab there are the following settings: + +#### Declaration of accessibility + +With these settings, you can add rich text content which will be shown on the declaration of accessibility page. + +#### Accessibility support + +With these settings, you can add rich text content and configure the form which will be shown on the accessibility support page. + #### Tab "Information banners" In this tab, you can enable and configure multiple information banners to be shown on selected pages. @@ -838,6 +850,6 @@ Moodle an Hochschulen e.V. would like to thank these main contributors (in alpha * Technische Universität Berlin, Lars Bonczek: Code * University of Graz, André Menrath: Code * University of Lübeck, Christian Wolters: Code, Peer Review, Ideating -* Zurich University of Applied Sciences (ZHAW): Funding, Ideating +* Zurich University of Applied Sciences (ZHAW): Funding, Ideating, Code Additionally, we thank all other contributors who contributed ideas, feedback and code snippets within the Github issues and pull requests as well as all contributors who contributed additional translations in AMOS, the Moodle translation tool. diff --git a/amd/build/accessibilitysupportform.min.js b/amd/build/accessibilitysupportform.min.js new file mode 100644 index 00000000000..754fcd10651 --- /dev/null +++ b/amd/build/accessibilitysupportform.min.js @@ -0,0 +1,12 @@ +define("theme_boost_union/accessibilitysupportform",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0;_exports.init=config=>{! +/** + * Theme Boost Union - JS code accessibility support form + * + * @module theme_boost_union/accessibilitysupportform + * @copyright 2024 Simon Schoenenberger + * @copyright on behalf of Zurich University of Applied Sciences (ZHAW) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +function(form){const systemInfoField=form.querySelector("[name=techinfo]");if(!systemInfoField)return;const replaceFields={systeminfo:['windowSize="'.concat(window.innerWidth,"×").concat(window.innerHeight,'"'),"prefersReducedMotion=".concat(window.matchMedia("(prefers-reduced-motion: reduce)").matches),"prefersMoreContrast=".concat(window.matchMedia("(prefers-contrast: more)").matches),"invertedColors=".concat(window.matchMedia("(inverted-colors: inverted)").matches),'vendor="'.concat(navigator.vendor,'"'),'userAgent="'.concat(navigator.userAgent,'"')].join("\n")};var infoMessage=systemInfoField.value;for(let field in replaceFields){let value=replaceFields[field];infoMessage=infoMessage.replace("{".concat(field,"}"),value)}systemInfoField.value=infoMessage,systemInfoField.readOnly=!0}(document.getElementById(config.formId))}})); + +//# sourceMappingURL=accessibilitysupportform.min.js.map \ No newline at end of file diff --git a/amd/build/accessibilitysupportform.min.js.map b/amd/build/accessibilitysupportform.min.js.map new file mode 100644 index 00000000000..cfa605da358 --- /dev/null +++ b/amd/build/accessibilitysupportform.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"accessibilitysupportform.min.js","sources":["../src/accessibilitysupportform.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Theme Boost Union - JS code accessibility support form\n *\n * @module theme_boost_union/accessibilitysupportform\n * @copyright 2024 Simon Schoenenberger \n * @copyright on behalf of Zurich University of Applied Sciences (ZHAW)\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * Fill form fields with system information.\n *\n * @param {HTMLElement} form\n */\nfunction fillFormFields(form) {\n const systemInfoField = form.querySelector('[name=techinfo]');\n\n if (!systemInfoField) {\n return;\n }\n\n const systemInfo = [\n `windowSize=\"${window.innerWidth}×${window.innerHeight}\"`,\n `prefersReducedMotion=${window.matchMedia('(prefers-reduced-motion: reduce)').matches}`,\n `prefersMoreContrast=${window.matchMedia('(prefers-contrast: more)').matches}`,\n `invertedColors=${window.matchMedia('(inverted-colors: inverted)').matches}`,\n `vendor=\"${navigator.vendor}\"`,\n `userAgent=\"${navigator.userAgent}\"`,\n ];\n const replaceFields = {\n 'systeminfo': systemInfo.join('\\n'),\n };\n\n var infoMessage = systemInfoField.value;\n\n for (let field in replaceFields) {\n let value = replaceFields[field];\n infoMessage = infoMessage.replace(`{${field}}`, value);\n }\n\n systemInfoField.value = infoMessage;\n // Only set readable. Browser does not send field value if field is disabled.\n systemInfoField.readOnly = true;\n}\n\nexport const init = (config) => {\n const form = document.getElementById(config.formId);\n fillFormFields(form);\n};\n"],"names":["config","form","systemInfoField","querySelector","replaceFields","window","innerWidth","innerHeight","matchMedia","matches","navigator","vendor","userAgent","join","infoMessage","value","field","replace","readOnly","fillFormFields","document","getElementById","formId"],"mappings":"+KA4DqBA;;;;;;;;;SA/BGC,YACdC,gBAAkBD,KAAKE,cAAc,uBAEtCD,6BAYCE,cAAgB,YARH,uBACAC,OAAOC,uBAAcD,OAAOE,gDACnBF,OAAOG,WAAW,oCAAoCC,uCACvDJ,OAAOG,WAAW,4BAA4BC,kCACnDJ,OAAOG,WAAW,+BAA+BC,2BACxDC,UAAUC,iCACPD,UAAUE,gBAGCC,KAAK,WAG9BC,YAAcZ,gBAAgBa,UAE7B,IAAIC,SAASZ,cAAe,KACzBW,MAAQX,cAAcY,OAC1BF,YAAcA,YAAYG,mBAAYD,WAAUD,OAGpDb,gBAAgBa,MAAQD,YAExBZ,gBAAgBgB,UAAW,EAK3BC,CADaC,SAASC,eAAerB,OAAOsB"} \ No newline at end of file diff --git a/amd/build/backtotopbutton.min.js b/amd/build/backtotopbutton.min.js index ee2a5e91c15..be1d293963c 100644 --- a/amd/build/backtotopbutton.min.js +++ b/amd/build/backtotopbutton.min.js @@ -7,6 +7,6 @@ * @copyright based on code from theme_boost_campus by Kathrin Osswald. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("theme_boost_union/backtotopbutton",["jquery","core/str","core/notification"],(function($,str,Notification){let buttonShown=!1;function checkAndHide(){!0===buttonShown&&$("#back-to-top").fadeOut(100,(function(){buttonShown=!1}))}function checkAndShow(){!1===buttonShown&&$("#back-to-top").fadeIn(300,(function(){buttonShown=!0}))}return{init:function(){!function(){let stringsPromise=str.get_string("backtotop","theme_boost_union");$.when(stringsPromise).then((function(string){return $("#page-footer").after(''),$(window).scrollTop()>220?checkAndShow():checkAndHide(),$(window).on("scroll",(function(){$(window).scrollTop()>220?checkAndShow():checkAndHide()})),$("#back-to-top").on("click",(function(event){event.preventDefault(),$("html, body").animate({scrollTop:0},500),$("#back-to-top").blur()})),$("#page-footer .btn-footer-communication").length&&$("body").addClass("theme-boost-union-commincourse"),!0})).fail(Notification.exception)}()}}})); +define("theme_boost_union/backtotopbutton",["jquery","core/str","core/notification"],(function($,str,Notification){let buttonShown=!1;function checkAndHide(){!0===buttonShown&&$("#back-to-top").fadeOut(100,(function(){buttonShown=!1}))}function checkAndShow(){!1===buttonShown&&$("#back-to-top").fadeIn(300,(function(){buttonShown=!0}))}return{init:function(){!function(){let stringsPromise=str.get_string("backtotop","theme_boost_union");$.when(stringsPromise).then((function(string){return $("#top-buttons").prepend(''),$(window).scrollTop()>220?checkAndShow():checkAndHide(),$(window).on("scroll",(function(){$(window).scrollTop()>220?checkAndShow():checkAndHide()})),$("#back-to-top").on("click",(function(event){event.preventDefault(),$("html, body").animate({scrollTop:0},500),$("#back-to-top").blur()})),$("#page-footer .btn-footer-communication").length&&$("body").addClass("theme-boost-union-commincourse"),!0})).fail(Notification.exception)}()}}})); //# sourceMappingURL=backtotopbutton.min.js.map \ No newline at end of file diff --git a/amd/build/backtotopbutton.min.js.map b/amd/build/backtotopbutton.min.js.map index 01dea03d1c9..4db95275655 100644 --- a/amd/build/backtotopbutton.min.js.map +++ b/amd/build/backtotopbutton.min.js.map @@ -1 +1 @@ -{"version":3,"file":"backtotopbutton.min.js","sources":["../src/backtotopbutton.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Theme Boost Union - JS code back to top button\n *\n * @module theme_boost_union/backtotopbutton\n * @copyright 2022 Alexander Bias, lern.link GmbH \n * @copyright on behalf of Zurich University of Applied Sciences (ZHAW)\n * @copyright based on code from theme_boost_campus by Kathrin Osswald.\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/str', 'core/notification'], function($, str, Notification) {\n \"use strict\";\n\n // Remember if the back to top button is shown currently.\n let buttonShown = false;\n\n /**\n * Initializing.\n */\n function initBackToTop() {\n // Define the scroll distance after which the button will be shown.\n const scrolldistance = 220;\n\n // Get the string backtotop from language file.\n let stringsPromise = str.get_string('backtotop', 'theme_boost_union');\n\n // If the string has arrived, add backtotop button to DOM and add scroll and click handlers.\n $.when(stringsPromise).then(function(string) {\n // Add a fontawesome icon after the footer as the back to top button.\n $('#page-footer').after('');\n\n // Check directly if the button should be shown.\n // This is helpful for all cases when this code here runs _after_ the page has been scrolled,\n // especially by the scrollspy feature or by a simple browser page reload.\n if ($(window).scrollTop() > scrolldistance) {\n checkAndShow();\n } else {\n checkAndHide();\n }\n\n // This function fades the button in when the page is scrolled down or fades it out\n // if the user is at the top of the page again.\n $(window).on('scroll', function() {\n if ($(window).scrollTop() > scrolldistance) {\n checkAndShow();\n } else {\n checkAndHide();\n }\n });\n\n // This function scrolls the page to top with a duration of 500ms.\n $('#back-to-top').on('click', function(event) {\n event.preventDefault();\n $('html, body').animate({scrollTop: 0}, 500);\n $('#back-to-top').blur();\n });\n\n // This will check if there is a communication button shown on the page already.\n // If yes, it will add a class to the body tag which will be later used to align the back-to-top button\n // with the communications button.\n // This is necessary as the communications button would otherwise be overlaid by the back-to-top button.\n if ($('#page-footer .btn-footer-communication').length) {\n $('body').addClass('theme-boost-union-commincourse');\n }\n\n return true;\n }).fail(Notification.exception);\n }\n\n /**\n * Helper function to handle the button visibility when the page is scrolling up.\n */\n function checkAndHide() {\n // Check if the button is still shown.\n if (buttonShown === true) {\n // Fade it out and remember the status in the end.\n // To be precise, the faceOut() function will be called multiple times as buttonShown is not set until the button is\n // really faded out. However, as soon as it is faded out, it won't be called until the button is shown again.\n $('#back-to-top').fadeOut(100, function() {\n buttonShown = false;\n });\n }\n }\n\n /**\n * Helper function to handle the button visibility when the page is scrolling down.\n */\n function checkAndShow() {\n // Check if the button is not yet shown.\n if (buttonShown === false) {\n // Fade it in and remember the status in the end.\n $('#back-to-top').fadeIn(300, function() {\n buttonShown = true;\n });\n }\n }\n\n return {\n init: function() {\n initBackToTop();\n }\n };\n});\n"],"names":["define","$","str","Notification","buttonShown","checkAndHide","fadeOut","checkAndShow","fadeIn","init","stringsPromise","get_string","when","then","string","after","window","scrollTop","on","event","preventDefault","animate","blur","length","addClass","fail","exception","initBackToTop"],"mappings":";;;;;;;;;AAyBAA,2CAAO,CAAC,SAAU,WAAY,sBAAsB,SAASC,EAAGC,IAAKC,kBAI7DC,aAAc,WA6DTC,gBAEe,IAAhBD,aAIAH,EAAE,gBAAgBK,QAAQ,KAAK,WAC3BF,aAAc,cAQjBG,gBAEe,IAAhBH,aAEAH,EAAE,gBAAgBO,OAAO,KAAK,WAC1BJ,aAAc,WAKnB,CACHK,KAAM,2BA7EFC,eAAiBR,IAAIS,WAAW,YAAa,qBAGjDV,EAAEW,KAAKF,gBAAgBG,MAAK,SAASC,eAEjCb,EAAE,gBAAgBc,MAAM,qGAECD,OAFD,yEAQpBb,EAAEe,QAAQC,YAhBK,IAiBfV,eAEAF,eAKJJ,EAAEe,QAAQE,GAAG,UAAU,WACfjB,EAAEe,QAAQC,YAzBC,IA0BXV,eAEAF,kBAKRJ,EAAE,gBAAgBiB,GAAG,SAAS,SAASC,OACnCA,MAAMC,iBACNnB,EAAE,cAAcoB,QAAQ,CAACJ,UAAW,GAAI,KACxChB,EAAE,gBAAgBqB,UAOlBrB,EAAE,0CAA0CsB,QAC5CtB,EAAE,QAAQuB,SAAS,mCAGhB,KACRC,KAAKtB,aAAauB,WAiCjBC"} \ No newline at end of file +{"version":3,"file":"backtotopbutton.min.js","sources":["../src/backtotopbutton.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Theme Boost Union - JS code back to top button\n *\n * @module theme_boost_union/backtotopbutton\n * @copyright 2022 Alexander Bias, lern.link GmbH \n * @copyright on behalf of Zurich University of Applied Sciences (ZHAW)\n * @copyright based on code from theme_boost_campus by Kathrin Osswald.\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/str', 'core/notification'], function($, str, Notification) {\n \"use strict\";\n\n // Remember if the back to top button is shown currently.\n let buttonShown = false;\n\n /**\n * Initializing.\n */\n function initBackToTop() {\n // Define the scroll distance after which the button will be shown.\n const scrolldistance = 220;\n\n // Get the string backtotop from language file.\n let stringsPromise = str.get_string('backtotop', 'theme_boost_union');\n\n // If the string has arrived, add backtotop button to DOM and add scroll and click handlers.\n $.when(stringsPromise).then(function(string) {\n // Add a fontawesome icon after the footer as the back to top button.\n $('#top-buttons').prepend('');\n\n // Check directly if the button should be shown.\n // This is helpful for all cases when this code here runs _after_ the page has been scrolled,\n // especially by the scrollspy feature or by a simple browser page reload.\n if ($(window).scrollTop() > scrolldistance) {\n checkAndShow();\n } else {\n checkAndHide();\n }\n\n // This function fades the button in when the page is scrolled down or fades it out\n // if the user is at the top of the page again.\n $(window).on('scroll', function() {\n if ($(window).scrollTop() > scrolldistance) {\n checkAndShow();\n } else {\n checkAndHide();\n }\n });\n\n // This function scrolls the page to top with a duration of 500ms.\n $('#back-to-top').on('click', function(event) {\n event.preventDefault();\n $('html, body').animate({scrollTop: 0}, 500);\n $('#back-to-top').blur();\n });\n\n // This will check if there is a communication button shown on the page already.\n // If yes, it will add a class to the body tag which will be later used to align the back-to-top button\n // with the communications button.\n // This is necessary as the communications button would otherwise be overlaid by the back-to-top button.\n if ($('#page-footer .btn-footer-communication').length) {\n $('body').addClass('theme-boost-union-commincourse');\n }\n\n return true;\n }).fail(Notification.exception);\n }\n\n /**\n * Helper function to handle the button visibility when the page is scrolling up.\n */\n function checkAndHide() {\n // Check if the button is still shown.\n if (buttonShown === true) {\n // Fade it out and remember the status in the end.\n // To be precise, the faceOut() function will be called multiple times as buttonShown is not set until the button is\n // really faded out. However, as soon as it is faded out, it won't be called until the button is shown again.\n $('#back-to-top').fadeOut(100, function() {\n buttonShown = false;\n });\n }\n }\n\n /**\n * Helper function to handle the button visibility when the page is scrolling down.\n */\n function checkAndShow() {\n // Check if the button is not yet shown.\n if (buttonShown === false) {\n // Fade it in and remember the status in the end.\n $('#back-to-top').fadeIn(300, function() {\n buttonShown = true;\n });\n }\n }\n\n return {\n init: function() {\n initBackToTop();\n }\n };\n});\n"],"names":["define","$","str","Notification","buttonShown","checkAndHide","fadeOut","checkAndShow","fadeIn","init","stringsPromise","get_string","when","then","string","prepend","window","scrollTop","on","event","preventDefault","animate","blur","length","addClass","fail","exception","initBackToTop"],"mappings":";;;;;;;;;AAyBAA,2CAAO,CAAC,SAAU,WAAY,sBAAsB,SAASC,EAAGC,IAAKC,kBAI7DC,aAAc,WA6DTC,gBAEe,IAAhBD,aAIAH,EAAE,gBAAgBK,QAAQ,KAAK,WAC3BF,aAAc,cAQjBG,gBAEe,IAAhBH,aAEAH,EAAE,gBAAgBO,OAAO,KAAK,WAC1BJ,aAAc,WAKnB,CACHK,KAAM,2BA7EFC,eAAiBR,IAAIS,WAAW,YAAa,qBAGjDV,EAAEW,KAAKF,gBAAgBG,MAAK,SAASC,eAEjCb,EAAE,gBAAgBc,QAAQ,qGAEDD,OAFC,yEAQtBb,EAAEe,QAAQC,YAhBK,IAiBfV,eAEAF,eAKJJ,EAAEe,QAAQE,GAAG,UAAU,WACfjB,EAAEe,QAAQC,YAzBC,IA0BXV,eAEAF,kBAKRJ,EAAE,gBAAgBiB,GAAG,SAAS,SAASC,OACnCA,MAAMC,iBACNnB,EAAE,cAAcoB,QAAQ,CAACJ,UAAW,GAAI,KACxChB,EAAE,gBAAgBqB,UAOlBrB,EAAE,0CAA0CsB,QAC5CtB,EAAE,QAAQuB,SAAS,mCAGhB,KACRC,KAAKtB,aAAauB,WAiCjBC"} \ No newline at end of file diff --git a/amd/src/accessibilitysupportform.js b/amd/src/accessibilitysupportform.js new file mode 100644 index 00000000000..60970a1248f --- /dev/null +++ b/amd/src/accessibilitysupportform.js @@ -0,0 +1,64 @@ +// 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 . + +/** + * Theme Boost Union - JS code accessibility support form + * + * @module theme_boost_union/accessibilitysupportform + * @copyright 2024 Simon Schoenenberger + * @copyright on behalf of Zurich University of Applied Sciences (ZHAW) + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +/** + * Fill form fields with system information. + * + * @param {HTMLElement} form + */ +function fillFormFields(form) { + const systemInfoField = form.querySelector('[name=techinfo]'); + + if (!systemInfoField) { + return; + } + + const systemInfo = [ + `windowSize="${window.innerWidth}×${window.innerHeight}"`, + `prefersReducedMotion=${window.matchMedia('(prefers-reduced-motion: reduce)').matches}`, + `prefersMoreContrast=${window.matchMedia('(prefers-contrast: more)').matches}`, + `invertedColors=${window.matchMedia('(inverted-colors: inverted)').matches}`, + `vendor="${navigator.vendor}"`, + `userAgent="${navigator.userAgent}"`, + ]; + const replaceFields = { + 'systeminfo': systemInfo.join('\n'), + }; + + var infoMessage = systemInfoField.value; + + for (let field in replaceFields) { + let value = replaceFields[field]; + infoMessage = infoMessage.replace(`{${field}}`, value); + } + + systemInfoField.value = infoMessage; + // Only set readable. Browser does not send field value if field is disabled. + systemInfoField.readOnly = true; +} + +export const init = (config) => { + const form = document.getElementById(config.formId); + fillFormFields(form); +}; diff --git a/amd/src/backtotopbutton.js b/amd/src/backtotopbutton.js index fdd51559e04..9864fd1a617 100644 --- a/amd/src/backtotopbutton.js +++ b/amd/src/backtotopbutton.js @@ -42,7 +42,7 @@ define(['jquery', 'core/str', 'core/notification'], function($, str, Notificatio // If the string has arrived, add backtotop button to DOM and add scroll and click handlers. $.when(stringsPromise).then(function(string) { // Add a fontawesome icon after the footer as the back to top button. - $('#page-footer').after(''); diff --git a/classes/form/accessibilitysupport_form.php b/classes/form/accessibilitysupport_form.php new file mode 100644 index 00000000000..62d40130f81 --- /dev/null +++ b/classes/form/accessibilitysupport_form.php @@ -0,0 +1,169 @@ +. + +namespace theme_boost_union\form; + +defined('MOODLE_INTERNAL') || die; + +require_once($CFG->dirroot.'/lib/formslib.php'); + +/** + * Theme Boost Union - Accessibility support form. + * + * @package theme_boost_union + * @copyright 2024 Katalin Lukacs Toth, ZHAW Zurich University of Applied Sciences + * @copyright 2024 Simon Schoenenberger, ZHAW Zurich University of Applied Sciences + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class accessibilitysupport_form extends \moodleform { + + /** + * Define the accessibility support form. + */ + public function definition(): void { + global $CFG, $USER; + + $mform = $this->_form; + $strrequired = get_string('required'); + + $sendanonymoussetting = get_config('theme_boost_union', 'enablesendanonymouscheckbox'); + if ($sendanonymoussetting == THEME_BOOST_UNION_SETTING_SELECT_YES && isloggedin() && !isguestuser()) { + // Checkbox to submit anonymously. + $accessibilitysupportanonymous = get_string('accessibilitysupportanonymouscheckbox', 'theme_boost_union'); + $mform->addElement('advcheckbox', 'sendanonymous', $accessibilitysupportanonymous); + $mform->setDefault('sendanonymous', 0); + } else { + $mform->addElement('hidden', 'sendanonymous', 0); + $mform->setType('sendanonymous', PARAM_BOOL); + } + + // Name. + $mform->addElement('text', 'name', get_string('name')); + $mform->addRule('name', $strrequired, 'required', null, 'client'); + $mform->setType('name', PARAM_TEXT); + $mform->hideIf('name', 'sendanonymous', 'checked'); + + // Email. + $mform->addElement('text', 'email', get_string('email')); + $mform->addRule('email', get_string('missingemail'), 'required', null, 'client'); + $mform->setType('email', PARAM_EMAIL); + $mform->hideIf('email', 'sendanonymous', 'checked'); + + // Subject. + $mform->addElement('text', 'subject', get_string('subject')); + $mform->setType('subject', PARAM_TEXT); + $mform->setDefault('subject', get_string('accessibilitysupportdefaultsubject', 'theme_boost_union')); + + // Message. + $mform->addElement('textarea', 'message', get_string('message')); + $mform->addRule('message', $strrequired, 'required', null, 'client'); + $mform->setType('message', PARAM_TEXT); + + $enablesendtechinfo = get_config('theme_boost_union', 'enablesendtechinfocheckbox'); + if ($enablesendtechinfo == THEME_BOOST_UNION_SETTING_SELECT_YES) { + // Checkbox to agree to the sending technical information, checked by default. + $accessibilitysupporttechinfo = get_string('accessibilitysupporttechinfocheckbox', 'theme_boost_union'); + $mform->addElement('advcheckbox', 'sendtechinfo', $accessibilitysupporttechinfo); + $mform->setDefault('sendtechinfo', 1); + } else { + $mform->addElement('hidden', 'sendtechinfo', 1); + $mform->setType('sendtechinfo', PARAM_BOOL); + } + + // Technical information. + $mform->addElement('textarea', 'techinfo', get_string('accessibilitysupporttechinfolabel', 'theme_boost_union')); + $mform->setType('techinfo', PARAM_TEXT); + $mform->setDefault('techinfo', get_string('accessibilitysysteminfomessage', 'theme_boost_union', [ + 'referrerpage' => $this->get_referrer_page(), + ])); + if ($enablesendtechinfo == THEME_BOOST_UNION_SETTING_SELECT_YES) { + $mform->hideIf('techinfo', 'sendtechinfo', 'notchecked'); + } + + // If the user is logged in set name and email fields to the current user info. + if (isloggedin() && !isguestuser()) { + $mform->setDefault('name', fullname($USER)); + $mform->hardFreeze('name'); + + $mform->setDefault('email', $USER->email); + $mform->hardFreeze('email'); + } + + if (!empty($CFG->recaptchapublickey) && !empty($CFG->recaptchaprivatekey)) { + $mform->addElement('recaptcha', 'recaptcha_element', get_string('security_question', 'auth')); + $mform->addHelpButton('recaptcha_element', 'recaptcha', 'auth'); + $mform->closeHeaderBefore('recaptcha_element'); + } + + $this->add_action_buttons(true, get_string('submit')); + } + + /** + * Validate user supplied data on the accessibility support form. + * + * @param array $data array of ("fieldname"=>value) of submitted data + * @param array $files array of uploaded files "element_name"=>tmp_file_path + * @return array of "element_name"=>"error_description" if there are errors, + * or an empty array if everything is OK (true allowed for backwards compatibility too). + */ + public function validation($data, $files): array { + $errors = parent::validation($data, $files); + if (!validate_email($data['email'])) { + $errors['email'] = get_string('invalidemail'); + } + if ($this->_form->elementExists('recaptcha_element')) { + $recaptchaelement = $this->_form->getElement('recaptcha_element'); + + if (!empty($this->_form->_submitValues['g-recaptcha-response'])) { + $response = $this->_form->_submitValues['g-recaptcha-response']; + if (!$recaptchaelement->verify($response)) { + $errors['recaptcha_element'] = get_string('incorrectpleasetryagain', 'auth'); + } + } else { + $errors['recaptcha_element'] = get_string('missingrecaptchachallengefield'); + } + } + + return $errors; + } + + /** + * Get the "id" attribute for this form. + * + * @return string + */ + public function get_id(): string { + return $this->_form->getAttribute('id'); + } + + /** + * Get the referrer page for this form. + * + * @return string + */ + public function get_referrer_page(): string { + global $SESSION; + + $referrer = $_SERVER['HTTP_REFERER'] ?? ''; + + // Save referrer page if set and not the form itself. + if ($referrer && strpos($referrer, 'accessibilitysupport.php') === false) { + $SESSION->boost_union_accessibility_pagereferrer = $referrer; + } + + return $SESSION->boost_union_accessibility_pagereferrer ?? ''; + } +} diff --git a/classes/local/hook/output/before_standard_top_of_body_html_generation.php b/classes/local/hook/output/before_standard_top_of_body_html_generation.php new file mode 100644 index 00000000000..9d618ad9f18 --- /dev/null +++ b/classes/local/hook/output/before_standard_top_of_body_html_generation.php @@ -0,0 +1,49 @@ +. + +/** + * Theme Boost Union - Hook: Allows plugins to add any elements on top of the page html tag. + * + * @package theme_boost_union + * @copyright 2024 Alexander Bias + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace theme_boost_union\local\hook\output; + +/** + * Hook to allow plugins to add any elements on top of the page html tag. + * + * @package theme_boost_union + * @copyright 2024 Alexander Bias + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class before_standard_top_of_body_html_generation { + /** + * Callback to add body elements. + * + * @param \core\hook\output\before_standard_top_of_body_html_generation $hook + */ + public static function callback(\core\hook\output\before_standard_top_of_body_html_generation $hook): void { + global $CFG; + + // Require local library. + require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + + // Call callback implementation. + theme_boost_union_callbackimpl_before_standard_top_of_body_html($hook); + } +} diff --git a/db/hooks.php b/db/hooks.php index ac78fd841ef..09f77b246e4 100644 --- a/db/hooks.php +++ b/db/hooks.php @@ -30,4 +30,9 @@ 'callback' => 'theme_boost_union\local\hook\output\before_standard_head_html_generation::callback', 'priority' => 0, ], + [ + 'hook' => \core\hook\output\before_standard_top_of_body_html_generation::class, + 'callback' => 'theme_boost_union\local\hook\output\before_standard_top_of_body_html_generation::callback', + 'priority' => 0, + ], ]; diff --git a/lang/en/theme_boost_union.php b/lang/en/theme_boost_union.php index 1c2fa2eb024..bbf7258cd77 100644 --- a/lang/en/theme_boost_union.php +++ b/lang/en/theme_boost_union.php @@ -861,6 +861,74 @@ $string['page3linkpositionboth'] = 'Add a link to the generic page 3 to the footnote and to the footer (questionmark) icon'; $string['page3linkpositionsetting'] = 'Generic page 3 link position'; $string['page3linkpositionsetting_desc'] = 'In this setting, you can configure if a link to the generic page 3 should be added automatically to the Moodle page. If you do not want to show a link automatically, you can add a link to {$a->url} from anywhere in Moodle manually.'; +// Settings: Accessibility tab. +$string['accessibilitytab'] = 'Accessibility'; +// ... Section: Declaration of accessibility page. +$string['accessibilityheading'] = 'Declaration of accessibility'; +// ... ... Setting: Enable accessibility page. +$string['enableaccessibilitysetting'] = 'Enable Declaration of accessibility information page'; +$string['accessibilitydisabled'] = 'The declaration of accessibility information page is disabled for this site. There is nothing to see here.'; +// ... ... Setting: Declaration of accessibility page content. +$string['accessibilitycontentsetting'] = 'Declaration of accessibility information page content'; +$string['accessibilitycontentsetting_desc'] = 'In this setting, you can add rich text content which will be shown on a Declaration of accessibility information page.'; +$string['accessibilitycontentdefault'] = '

Informations about the accessibility of this site will be added here.

'; +// ... ... Setting: accessibility page title. +$string['accessibilitypagetitledefault'] = 'Declaration of accessibility'; +$string['accessibilitypagetitlesetting'] = 'Declaration of accessibility information page title'; +$string['accessibilitypagetitlesetting_desc'] = 'In this setting, you can define the title of the Declaration of accessibility information page. This text will be used as link text to the Declaration of accessibility information page as well if you configure \'Declaration of accessibility information page link position\' accordingly.'; +// ... ... Setting: Declaration of accessibility page link position. +$string['accessibilitylinkpositionnone'] = 'Do not automatically show a link to the Declaration of accessibility information page'; +$string['accessibilitylinkpositionfootnote'] = 'Add a link to the Declaration of accessibility information page to the footnote'; +$string['accessibilitylinkpositionfooter'] = 'Add a link to the Declaration of accessibility information page to the footer (questionmark) icon'; +$string['accessibilitylinkpositionboth'] = 'Add a link to the Declaration of accessibility information page to the footnote and to the footer (questionmark) icon'; +$string['accessibilitylinkpositionsetting'] = 'Declaration of accessibility information page link position'; +$string['accessibilitylinkpositionsetting_desc'] = 'In this setting, you can configure if a link to the Declaration of accessibility information page should be added automatically to the Moodle page. If you do not want to show a link automatically, you can add a link to {$a->url} from anywhere in Moodle manually.'; +// ... ... Setting: Enable accessibility button. +$string['enableaccessibilitybuttonsetting'] = 'Enable accessibility button in page navigation'; +$string['enableaccessibilitybuttonsetting_desc'] = 'Link to the accessibility form will be visible as accessibility icon above the footer (questionmark) icon.'; +// ... Section: Accessibility supportpage. +$string['accessibilitysupportheading'] = 'Accessibility support'; +// ... ... Setting: Enable Accessibility support page. +$string['enableaccessibilitysupportsetting'] = 'Enable accessibility support page'; +$string['accessibilitysupportdisabled'] = 'The accessibility support page is disabled for this site. There is nothing to see here.'; +$string['enableaccessibilitysupportwithoutlogin'] = 'Enable page to be shown without login'; +$string['enableaccessibilitysupportwithoutlogin_desc'] = 'Enable accessibility support page to be shown without login. If this setting is enabled, the accessibility support page will be shown to users who are not logged in. If this setting is disabled, the accessibility support page will be shown only to logged in users.'; +// ... ... Setting: Accessibility support page content. +$string['accessibilitysupportcontentsetting'] = 'Accessibility support information page content'; +$string['accessibilitysupportcontentsetting_desc'] = 'In this setting, you can add rich text content which will be shown on the Accessibility support information page. The page will contain a form to send feedback or to report a barrier. The following information can be sent along with the message: Moodle version, Referrer page, Systeminfo.'; +$string['accessibilitysupportcontentdefault'] = '

If you have any feedback or want to report a barrier, please use the form below.

Do you work with assistive technology such as screen readers, magnifiers, voice control or speech recognition software? If yes, please specify which ones. If you have any other feedback or want to report a barrier, please describe it here.

The following information can be sent along with your message: Moodle version, Referrer page, Systeminfo

'; +// ... ... Setting: Accessibility support page title. +$string['accessibilitysupportpagetitledefault'] = 'Accessibility support'; +$string['accessibilitysupportpagetitlesetting'] = 'Accessibility support information page title'; +$string['accessibilitysupportpagetitlesetting_desc'] = 'In this setting, you can define the title of the Accessibility support information page. This text will be used as link text to the Accessibility support information page as well if you configure \'Accessibility support information page link position\' accordingly.'; +// ... ... Setting: Accessibility support page link position. +$string['accessibilitysupportlinkpositionnone'] = 'Do not automatically show a link to the Accessibility support information page'; +$string['accessibilitysupportlinkpositionfootnote'] = 'Add a link to the Accessibility support information page to the footnote'; +$string['accessibilitysupportlinkpositionfooter'] = 'Add a link to the Accessibility support information page to the footer (questionmark) icon'; +$string['accessibilitysupportlinkpositionboth'] = 'Add a link to the Accessibility support information page to the footnote and to the footer (questionmark) icon'; +$string['accessibilitysupportlinkpositionsetting'] = 'Accessibility support information page link position'; +$string['accessibilitysupportlinkpositionsetting_desc'] = 'In this setting, you can configure if a link to the Accessibility support information page should be added automatically to the Moodle page. If you do not want to show a link automatically, you can add a link to {$a->url} from anywhere in Moodle manually.'; +// ... ... Setting: Accessibility support form +$string['enablesendanonymouscheckboxsetting'] = 'Enable anonymous checkbox in accessibility form'; +$string['enablesendanonymouscheckboxsetting_desc'] = 'With this setting, you can enable the checkbox to send feedback anonymously in the accessibility form. Users can decide if they want to send feedback anonymously (without sending their username and email address) or not.'; +$string['enablesendtechinfocheckboxsetting'] = 'Enable checkbox for sending technical information in accessibility form'; +$string['enablesendtechinfocheckboxsetting_desc'] = 'With this setting, you can enable the checkbox for sending technical information in the accessibility form. Users can decide if they want to send technical information.'; +$string['accessibilitysupportanonymouscheckbox'] = 'I prefer to send feedback anonymously'; +$string['accessibilitysupportdefaultsubject'] = 'Accessibility feedback / barrier report'; +$string['accessibilitysupportemailsubject'] = 'Accessibility feedback / barrier report - {$a}'; +$string['accessibilitysupporttechinfocheckbox'] = 'I agree to send the following technical information along with my message'; +$string['accessibilitysupporttechinfo'] = 'Technical information'; +$string['accessibilitysupporttechinfolabel'] = 'Technical information to send'; +$string['accessibilitysupportmessagesent'] = 'Accessibility feedback message sent'; +$string['accessibilitysysteminfomessage'] = "Referrer page:\n{\$a->referrerpage}\nSystem info:\n{systeminfo}"; +// ... ... Setting: Accessibility support email +$string['accessibilitysupportname'] = 'Accessibility support name'; +$string['accessibilitysupportname_desc'] = 'Name of the person or other entity providing accessibility support via the accessibility support form.'; +$string['accessibilitysupportemail'] = 'Accessibility support email'; +$string['accessibilitysupportemail_desc'] = 'Email address to which the feedback or barrier report should be sent. If you leave this field empty, the feedback will be sent to the site support email configured under \'Server / Support Contact\' or to the site administrator.'; +$string['accessibilitysupportsentforanonymoususer'] = 'User requested to send feedback anonymously'; +$string['accessibilitysupportanonymoususer'] = 'Anonymous user'; +$string['accessibilitysupportanonymousemail'] = 'anonymous@email'; // Settings: Info banners tab. $string['infobannertab'] = 'Info banner'; // ... Section: Info banners. @@ -1330,3 +1398,6 @@ $string['upgradenotice_2022080922_logocompact'] = 'compact logo'; $string['upgradenotice_2022080922_copied'] = 'The existing {$a} from the Moodle core settings has been copied to the Boost Union {$a} setting during this upgrade. Please double-check the result.'; $string['upgradenotice_2022080922_notcopied'] = 'The {$a} setting within Boost Union is empty now. If you want to use a {$a} within Boost Union from now on, just upload it into the Boost Union {$a} setting later.'; + +// Accessibility. +$string['sendaccessibilityfeedback'] = 'Send accessibility feedback'; diff --git a/layout/columns2.php b/layout/columns2.php index 92f8ed191a9..f97a8283de4 100644 --- a/layout/columns2.php +++ b/layout/columns2.php @@ -125,6 +125,9 @@ // Include the template content for the static pages. require_once(__DIR__ . '/includes/staticpages.php'); +// Include the template content for the accessibility pages. +require_once(__DIR__ . '/includes/accessibilitypages.php'); + // Include the template content for the footer button. require_once(__DIR__ . '/includes/footer.php'); diff --git a/layout/drawers.php b/layout/drawers.php index 2aa55798cc9..1f88e0e4b21 100644 --- a/layout/drawers.php +++ b/layout/drawers.php @@ -190,6 +190,9 @@ // Include the template content for the static pages. require_once(__DIR__ . '/includes/staticpages.php'); +// Include the template content for the accessibility pages. +require_once(__DIR__ . '/includes/accessibilitypages.php'); + // Include the template content for the footer button. require_once(__DIR__ . '/includes/footer.php'); diff --git a/layout/includes/accessibilitypages.php b/layout/includes/accessibilitypages.php new file mode 100644 index 00000000000..1711cc8df2f --- /dev/null +++ b/layout/includes/accessibilitypages.php @@ -0,0 +1,75 @@ +. + +/** + * Theme Boost Union - Accessibility pages layout include. + * + * @package theme_boost_union + * @copyright 2024 Katalin Lukacs Toth, ZHAW Zurich University of Applied Sciences + * @copyright 2024 Simon Schoenenberger, ZHAW Zurich University of Applied Sciences + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +// Require the necessary libraries. +require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + +$config = get_config('theme_boost_union'); + +// The static pages to be supported. +$pages = ['accessibility', 'accessibilitysupport']; + +// Initialize flags if any static page should be linked from the footer and footnote. +$templatecontext['anyaccessibilitypagelinkedfromfooter'] = false; +$templatecontext['anyaccessibilitypagelinkedfromfootnote'] = false; + +// Iterate over the static pages. +foreach ($pages as $page) { + // If the page is enabled. + if (isset($config->{'enable'.$page}) && + $config->{'enable'.$page} == THEME_BOOST_UNION_SETTING_SELECT_YES) { + // If the admin wants to show a link in the footnote or in both locations. + if ($config->{$page.'linkposition'} == THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTNOTE || + $config->{$page.'linkposition'} == THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_BOTH) { + // If the footnote is empty and not configured to be shown yet. + if (isset($templatecontext['showfootnote']) == false || $templatecontext['showfootnote'] == false) { + // Add marker to show the footnote to templatecontext. + $templatecontext['showfootnote'] = true; + } + + // Add marker to show the page link in the footnote to templatecontext. + $templatecontext[$page.'linkpositionfootnote'] = true; + + // Flip flag that at least one page should be linked from the footnote. + $templatecontext['anystaticpagelinkedfromfootnote'] = true; + } + + // If the admin wants to show a link in the footer or in both locations. + if ($config->{$page.'linkposition'} == THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTER || + $config->{$page.'linkposition'} == THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_BOTH) { + // Add marker to show the page link in the footer to templatecontext. + $templatecontext[$page.'linkpositionfooter'] = true; + + // Flip flag that at least one page should be linked from the footer. + $templatecontext['anyaccessibilitypagelinkedfromfooter'] = true; + } + + // Add the page link and page title to the templatecontext. + $templatecontext[$page.'link'] = theme_boost_union_get_staticpage_link($page); + $templatecontext[$page.'pagetitle'] = theme_boost_union_get_staticpage_pagetitle($page); + } +} diff --git a/layout/includes/footer.php b/layout/includes/footer.php index c258efc014a..64c9babecb3 100644 --- a/layout/includes/footer.php +++ b/layout/includes/footer.php @@ -141,5 +141,19 @@ // Add marker to hide the icons. $templatecontext['suppressfooterlinkicons'] = true; } +} +// If the accessibility button is enabled. +$enableaccessibilitysupportsetting = get_config('theme_boost_union', 'enableaccessibilitysupport'); +$accessibilitybuttonsetting = get_config('theme_boost_union', 'enableaccessibilitybutton'); +if ($enableaccessibilitysupportsetting == THEME_BOOST_UNION_SETTING_SELECT_YES && + $accessibilitybuttonsetting == THEME_BOOST_UNION_SETTING_SELECT_YES) { + // Add marker to show this link. + $templatecontext['accessibilitybutton'] = true; + $templatecontext['accessibilityformurl'] = new moodle_url('/theme/boost_union/pages/accessibilitysupport.php'); + + // Otherwise. +} else { + // Add marker to hide this link. + $templatecontext['accessibilitybutton'] = false; } diff --git a/layout/login.php b/layout/login.php index 7dd1b3ddb4a..7f01155bcf4 100644 --- a/layout/login.php +++ b/layout/login.php @@ -53,6 +53,9 @@ // Include the template content for the static pages. require_once(__DIR__ . '/includes/staticpages.php'); +// Include the template content for the accessibility pages. +require_once(__DIR__ . '/includes/accessibilitypages.php'); + // Include the template content for the footer button. require_once(__DIR__ . '/includes/footer.php'); diff --git a/lib.php b/lib.php index 8b7404dfe3e..e70004126fa 100644 --- a/lib.php +++ b/lib.php @@ -550,6 +550,23 @@ function theme_boost_union_before_standard_html_head() { return theme_boost_union_callbackimpl_before_standard_html(); } +/** + * Callback to add body elements on top (for releases up to Moodle 4.3). + * + * @return string + * @throws coding_exception + * @throws dml_exception + */ +function theme_boost_union_before_standard_top_of_body_html() { + global $CFG; + + // Require local library. + require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + + // Call and return callback implementation. + return theme_boost_union_callbackimpl_before_standard_top_of_body_html(); +} + /** * Fetches the list of icons and creates an icon suggestion list to be sent to a fragment. * diff --git a/locallib.php b/locallib.php index e6e9a366043..23af5e5d022 100644 --- a/locallib.php +++ b/locallib.php @@ -2067,6 +2067,54 @@ function theme_boost_union_callbackimpl_before_standard_html(&$hook = null) { } } +/** + * Callback to add body elements on top. + * This function is implemented here and used from two locations: + * -> function theme_boost_union_before_standard_top_of_body_html in lib.php (for releases up to Moodle 4.3) + * -> class theme_boost_union\local\hook\output\before_standard_top_of_body_html_generation (for releases from Moodle 4.4 on). + * + * We use this callback + * -> to add the accessibility form link + * + * @param \core\hook\output\before_standard_top_of_body_html_generation $hook If the hook is passed, the hook implementation will + * be used. If not, the legacy implementation will + * be used. + * @return string|void The legacy implementation will return a string, the hook implementation will return nothing. + */ +function theme_boost_union_callbackimpl_before_standard_top_of_body_html(&$hook = null) { + global $CFG, $PAGE; + + // Require local library. + require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + + // Initialize HTML. + $html = ''; + + // If a theme other than Boost Union or a child theme of it is active, return directly. + // This is necessary as the callback is called regardless of the active theme. + if ($PAGE->theme->name != 'boost_union' && !in_array('boost_union', $PAGE->theme->parents)) { + if ($hook != null) { + return; + } else { + return $html; + } + } + + // Require local library. + require_once($CFG->dirroot . '/theme/boost_union/locallib.php'); + + // Add the accessibility form skip link to the page. + $html .= theme_boost_union_get_accessibility_form_skip_link(); + + if ($hook != null) { + // Add the HTML code to the hook. + $hook->add_html($html); + } else { + // Return the HTML code. + return $html; + } +} + /** * Gets and returns the external SCSS based on the theme configuration. * @@ -2221,6 +2269,30 @@ function theme_boost_union_get_external_scss($type) { return $extscss; } +/** + * Build the link to the accessibility form visible for screen readers. + * + * @return string + * @throws coding_exception + * @throws dml_exception + */ +function theme_boost_union_get_accessibility_form_skip_link() { + $output = ''; + + $enableaccessibilitysupportsetting = get_config('theme_boost_union', 'enableaccessibilitysupport'); + if ($enableaccessibilitysupportsetting == THEME_BOOST_UNION_SETTING_SELECT_YES) { + // Add link for screen readers to accessibility feedback form. + $supporturl = new \moodle_url('/theme/boost_union/pages/accessibilitysupport.php'); + $supporttitle = get_string('sendaccessibilityfeedback', 'theme_boost_union'); + $output .= \html_writer::link($supporturl, $supporttitle, [ + 'id' => 'access-support-form-sr-link', + 'class' => 'sr-only sr-only-focusable', + ]); + } + + return $output; +} + /** * Helper function which wxtracts and returns the pluginname for the given callback name. * This function simply differentiates between real plugins and core components. diff --git a/pages/accessibility.php b/pages/accessibility.php new file mode 100644 index 00000000000..046c7a4a41b --- /dev/null +++ b/pages/accessibility.php @@ -0,0 +1,76 @@ +. + +/** + * Theme Boost Union - Declaration of accessibility page. + * + * @package theme_boost_union + * @copyright 2024 Katalin Lukacs Toth, ZHAW Zurich University of Applied Sciences + * @copyright 2024 Simon Schoenenberger, ZHAW Zurich University of Applied Sciences + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// Include config.php. +// @codingStandardsIgnoreStart +// Let codechecker ignore the next line because otherwise it would complain about a missing login check +// after requiring config.php which is really not needed. +require(__DIR__ . '/../../../config.php'); +// @codingStandardsIgnoreEnd + +// Require the necessary libraries. +require_once($CFG->dirroot.'/theme/boost_union/lib.php'); +require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + +// Set page URL. +$PAGE->set_url('/theme/boost_union/pages/accessibility.php'); + +// Set page layout. +$PAGE->set_pagelayout('standard'); + +// Set page context. +$PAGE->set_context(context_system::instance()); + +// Add page name as body class. +$PAGE->add_body_class('theme_boost_union-accessibility'); + +// Get theme config. +$config = get_config('theme_boost_union'); + +// If the Declaration of accessibility page is disabled, we just show a short friendly warning page and are done. +if ($config->enableaccessibility != THEME_BOOST_UNION_SETTING_SELECT_YES) { + echo $OUTPUT->header(); + $notification = new \core\output\notification(get_string('accessibilitydisabled', 'theme_boost_union'), + \core\output\notification::NOTIFY_INFO); + $notification->set_show_closebutton(false); + echo $OUTPUT->render($notification); + echo $OUTPUT->footer(); + die; +} + +// Set page title. +$PAGE->set_title(theme_boost_union_get_staticpage_pagetitle('accessibility')); + +// Start page output. +echo $OUTPUT->header(); + +// Show page heading. +echo $OUTPUT->heading(theme_boost_union_get_staticpage_pagetitle('accessibility')); + +// Output Declaration of accessibility page content. +echo format_text($config->accessibilitycontent, FORMAT_MOODLE, ['trusted' => true, 'noclean' => true]); + +// Finish page. +echo $OUTPUT->footer(); diff --git a/pages/accessibilitysupport.php b/pages/accessibilitysupport.php new file mode 100644 index 00000000000..9a12ffca56e --- /dev/null +++ b/pages/accessibilitysupport.php @@ -0,0 +1,160 @@ +. + +/** + * Theme Boost Union - Accessibility support page. + * + * @package theme_boost_union + * @copyright 2024 Katalin Lukacs Toth, ZHAW Zurich University of Applied Sciences + * @copyright 2024 Simon Schoenenberger, ZHAW Zurich University of Applied Sciences + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +// Include config.php. +// @codingStandardsIgnoreStart +// Let codechecker ignore the next line because otherwise it would complain about a missing login check +// after requiring config.php which is really not needed. +require(__DIR__ . '/../../../config.php'); +// @codingStandardsIgnoreEnd + +// Require the necessary libraries. +require_once($CFG->dirroot.'/theme/boost_union/lib.php'); +require_once($CFG->dirroot.'/theme/boost_union/locallib.php'); + +// Set page URL. +$PAGE->set_url('/theme/boost_union/pages/accessibilitysupport.php'); + +// Set page layout. +$PAGE->set_pagelayout('standard'); + +// Set page context. +$PAGE->set_context(context_system::instance()); + +// Add page name as body class. +$PAGE->add_body_class('theme_boost_union-accessibilitysupport'); + +// Get theme config. +$config = get_config('theme_boost_union'); + +// If the Accessibility supportpage is disabled, we just show a short friendly warning page and are done. +if ($config->enableaccessibilitysupport != THEME_BOOST_UNION_SETTING_SELECT_YES) { + echo $OUTPUT->header(); + $notification = new \core\output\notification(get_string('accessibilitysupportdisabled', 'theme_boost_union'), + \core\output\notification::NOTIFY_INFO); + $notification->set_show_closebutton(false); + echo $OUTPUT->render($notification); + echo $OUTPUT->footer(); + die; +} + +// If user login is required, we redirect to the login page. +if ($config->enableaccessibilitysupportwithoutlogin != THEME_BOOST_UNION_SETTING_SELECT_YES) { + if (!isloggedin() || isguestuser()) { + redirect(get_login_url()); + } +} + +// Set page title. +$PAGE->set_title(theme_boost_union_get_staticpage_pagetitle('accessibilitysupport')); + +$form = new \theme_boost_union\form\accessibilitysupport_form(); + +// Get the page where we came from. +$referrerpage = $form->get_referrer_page(); +if (!$referrerpage) { + $referrerpage = $CFG->wwwroot; +} + +if ($form->is_cancelled()) { + redirect($referrerpage); +} else if ($form->is_submitted() && $form->is_validated() && confirm_sesskey()) { + $data = $form->get_data(); + + // Do not send system information when not allowed. + if (!$data->sendtechinfo) { + unset($data->techinfo); + } + + $validuser = isloggedin() && !isguestuser(); + if ($validuser) { + $from = $USER; + $data->notloggedinuser = false; + } else { + $from = core_user::get_noreply_user(); + $data->notloggedinuser = true; + } + if ($data->sendanonymous) { + $from = core_user::get_noreply_user(); + $data->name = get_string('accessibilitysupportanonymoususer', 'theme_boost_union'); + $data->email = get_string('accessibilitysupportanonymousemail', 'theme_boost_union'); + } + + $subject = get_string('accessibilitysupportemailsubject', 'theme_boost_union', format_string($SITE->fullname)); + $renderer = $PAGE->get_renderer('core'); + $message = $renderer->render_from_template('theme_boost_union/accessibility_support_email_body', $data); + + $accessibilityemail = get_config('theme_boost_union', 'accessibilitysupportemail'); + $accessibilityname = get_config('theme_boost_union', 'accessibilitysupportname'); + if ($accessibilityemail) { + // We need to create a dummy user record to send the mail. + // The user record is only used to send the mail. + $supportuser = core_user::get_noreply_user(); + $supportuser->email = $accessibilityemail; + if ($accessibilityname) { + $supportuser->firstname = $accessibilityname; + } + } else { + $supportuser = core_user::get_support_user(); + } + + if (!email_to_user($supportuser, $from, $subject, $message)) { + $supportemail = $CFG->supportemail; + $form->set_data($data); + $templatectx = [ + 'supportemail' => $validuser ? html_writer::link("mailto:{$supportemail}", $supportemail) : false, + 'supportform' => $form->render(), + ]; + + $formoutput = $renderer->render_from_template('theme_boost_union/accessibility_support_not_available', $templatectx); + } else { + $level = \core\output\notification::NOTIFY_SUCCESS; + redirect($referrerpage, get_string('accessibilitysupportmessagesent', 'theme_boost_union'), 3, $level); + } +} else { + $formoutput = $form->render(); +} + +// Include form specific Javascript. +$PAGE->requires->js_call_amd('theme_boost_union/accessibilitysupportform', 'init', [ + [ + 'formId' => $form->get_id(), + ], +]); + +// Start page output. +echo $OUTPUT->header(); + +// Show page heading. +echo $OUTPUT->heading(theme_boost_union_get_staticpage_pagetitle('accessibilitysupport')); + +// Output Accessibility support page content. +echo format_text($config->accessibilitysupportcontent, FORMAT_MOODLE, ['trusted' => true, 'noclean' => true]); + +// Output the form. +echo $formoutput; + +// Finish page. +echo $OUTPUT->footer(); diff --git a/scss/boost_union/post.scss b/scss/boost_union/post.scss index 81a67237bdd..bd83d259ab0 100644 --- a/scss/boost_union/post.scss +++ b/scss/boost_union/post.scss @@ -532,9 +532,7 @@ body.hascourseindexcplsol.editing { * Setting: Back to top button. --------------------------------------*/ -#back-to-top { - /* Hide the back to top icon initially. It will be unhidden by JS only. */ - display: none; +#top-buttons { /* Place the back to top button at a fixed place. */ position: fixed; right: 2rem; @@ -544,9 +542,56 @@ body.hascourseindexcplsol.editing { z-index: $zindex-dropdown; /* Animate position together with footer button. */ @include transition(0.2s); + + /* Add margin between buttons. */ + .btn { + display: block; + margin-top: 0.75rem; + } + + /* Center icon in button. */ + .btn-accessibility-form { + display: flex; + align-items: center; + justify-content: center; + font-size: 1.75rem; + border: 6px solid #ced4da; + transition: 0.2s; + + .icon { + width: 1.75rem; + height: 1.75rem; + max-width: none; + max-height: none; + font-size: 1.75rem; + color: #ced4da; + transition: 0.2s; + } + + &, + &:hover, + &:focus { + background: #000 !important; /* stylelint-disable-line declaration-no-important */ + } + + &:hover, + &:focus { + border-color: #b1bbc4; + + .icon { + color: #b1bbc4; + } + } + } + + #back-to-top { + /* Hide the back to top icon initially. It will be unhidden by JS only. */ + display: none; + } } + /* If the sticky footer is shown by Moodle core, the back to top button has to have a higher starting position. */ -body.hasstickyfooter #back-to-top { +body.hasstickyfooter #top-buttons { bottom: 7rem; } #back-to-top i::before { @@ -559,14 +604,14 @@ body.hasstickyfooter #back-to-top { body.theme_boost-union-footerbuttonall.jsenabled, body.theme_boost-union-footerbuttonmobile.jsenabled { @include media-breakpoint-down(xs) { - #back-to-top { + #top-buttons { bottom: 5rem; } } /* And if the sticky footer is shown by Moodle core, move the back to top button more upwards. */ &.hasstickyfooter { @include media-breakpoint-down(xs) { - #back-to-top { + #top-buttons { bottom: 10rem; } } @@ -577,14 +622,14 @@ body.theme_boost-union-footerbuttonmobile.jsenabled { body.theme_boost-union-footerbuttonall.jsenabled, body.theme_boost-union-footerbuttondesktop.jsenabled { @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 5rem; } } /* And if the sticky footer is shown by Moodle core, move the back to top button more upwards. */ &.hasstickyfooter { @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 10rem; } } @@ -601,14 +646,14 @@ body.theme-boost-union-commincourse { &.theme_boost-union-footerbuttonmobile.jsenabled { /* We have to move the back to top button more upwards.*/ @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 5rem; } } /* And if the sticky footer is shown by Moodle core, move the back to top button more upwards. */ &.hasstickyfooter { @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 10rem; } } @@ -620,14 +665,14 @@ body.theme-boost-union-commincourse { &.theme_boost-union-footerbuttondesktop.jsenabled { /* We have to move the back to top button even more upwards.*/ @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 8rem; } } /* And if the sticky footer is shown by Moodle core, move the back to top button more upwards. */ &.hasstickyfooter { @include media-breakpoint-up(sm) { - #back-to-top { + #top-buttons { bottom: 13rem; } } @@ -636,13 +681,16 @@ body.theme-boost-union-commincourse { } /* If the right-hand drawer is opened. */ -#page.drawers.show-drawer-right #back-to-top { +#page.drawers.show-drawer-right #top-buttons { /* On larger screens, the drawer opens near the main content. The back to top button can be moved nicely to the left. */ @include media-breakpoint-up(lg) { /* Move the back to top button when right drawer is shown. */ right: calc(#{$drawer-right-width} + 2rem); } +} + +#page.drawers.show-drawer-right #back-to-top { /* On smaller screens, the drawer opens as an overlay over the main content. The back to top button looks misplaced then. */ @include media-breakpoint-down(lg) { @@ -2384,7 +2432,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { /* If the bottom bar is shown. */ body.theme-boost-union-bottombar { /* The back to top button has to be moved more upwards. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 1rem); } @@ -2396,7 +2444,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { bottom: calc(60px + 1rem); } /* And the back to top button has to be moved even more upwards. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 4rem); } } @@ -2407,7 +2455,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { /* If the bottom bar is shown. */ body.theme-boost-union-bottombar { /* The back to top button has to be moved more upwards. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 1rem); } @@ -2419,7 +2467,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { bottom: calc(60px + 1rem); } /* And the back to top button has to be moved even more upwards. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 4rem); } } @@ -2433,7 +2481,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { } /* The back to top button has to be moved even more upwards. This has to use !important as the selector above would be more specific otherwise. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 4rem) !important; /* stylelint-disable-line declaration-no-important */ } @@ -2450,7 +2498,7 @@ body.theme_boost-union-footerbuttonnone.jsenabled { } /* And the back to top button has to be moved even more upwards. This has to use !important as the selector above would be more specific otherwise. */ - #back-to-top { + #top-buttons { bottom: calc(60px + 7rem) !important; /* stylelint-disable-line declaration-no-important */ } } diff --git a/settings.php b/settings.php index beb6d5214ad..8c98a83c317 100644 --- a/settings.php +++ b/settings.php @@ -2097,6 +2097,172 @@ // Add tab to settings page. $page->add($tab); + // Create Accessibility tab. + $tab = new admin_settingpage('theme_boost_union_content_accessibility', + get_string('accessibilitytab', 'theme_boost_union', null, true)); + + // Create Declaration of accessibility page heading. + $name = 'theme_boost_union/accessibilityheading'; + $title = get_string('accessibilityheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Enable Declaration of accessibility page. + $name = 'theme_boost_union/enableaccessibility'; + $title = get_string('enableaccessibilitysetting', 'theme_boost_union', null, true); + $description = ''; + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, + $yesnooption); + $tab->add($setting); + + // Setting: Declaration of accessibility page content. + $name = 'theme_boost_union/accessibilitycontent'; + $title = get_string('accessibilitycontentsetting', 'theme_boost_union', null, true); + $description = get_string('accessibilitycontentsetting_desc', 'theme_boost_union', null, true); + $default = get_string('accessibilitycontentdefault', 'theme_boost_union', null, true); + $setting = new admin_setting_confightmleditor($name, $title, $description, $default); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitycontent', 'theme_boost_union/enableaccessibility', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Setting: Declaration of accessibility page title. + $name = 'theme_boost_union/accessibilitypagetitle'; + $title = get_string('accessibilitypagetitlesetting', 'theme_boost_union', null, true); + $description = get_string('accessibilitypagetitlesetting_desc', 'theme_boost_union', null, true); + $default = get_string('accessibilitypagetitledefault', 'theme_boost_union', null, true); + $setting = new admin_setting_configtext($name, $title, $description, $default); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitypagetitle', 'theme_boost_union/enableaccessibility', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Setting: Declaration of accessibility page link position. + $name = 'theme_boost_union/accessibilitylinkposition'; + $title = get_string('accessibilitylinkpositionsetting', 'theme_boost_union', null, true); + $pageurl = theme_boost_union_get_staticpage_link('accessibility'); + $description = get_string('accessibilitylinkpositionsetting_desc', 'theme_boost_union', ['url' => $pageurl], + true); + $linkpositionoption = + // Don't use string lazy loading (= false) because the string will be directly used and would produce a + // PHP warning otherwise. + [THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_NONE => + get_string('accessibilitylinkpositionnone', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTNOTE => + get_string('accessibilitylinkpositionfootnote', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTER => + get_string('accessibilitylinkpositionfooter', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_BOTH => + get_string('accessibilitylinkpositionboth', 'theme_boost_union', null, false), ]; + $default = 'none'; + $setting = new admin_setting_configselect($name, $title, $description, $default, $linkpositionoption); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitylinkposition', 'theme_boost_union/enableaccessibility', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Create Accessibility support page heading. + $name = 'theme_boost_union/accessibilitysupportheading'; + $title = get_string('accessibilitysupportheading', 'theme_boost_union', null, true); + $setting = new admin_setting_heading($name, $title, null); + $tab->add($setting); + + // Setting: Enable Accessibility support page. + $name = 'theme_boost_union/enableaccessibilitysupport'; + $title = get_string('enableaccessibilitysupportsetting', 'theme_boost_union', null, true); + $description = ''; + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, + $yesnooption); + $tab->add($setting); + + // Setting: Enable Accessibility support page without login. + $name = 'theme_boost_union/enableaccessibilitysupportwithoutlogin'; + $title = get_string('enableaccessibilitysupportwithoutlogin', 'theme_boost_union', null, true); + $description = get_string('enableaccessibilitysupportwithoutlogin_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, + $yesnooption); + $tab->add($setting); + + // Setting: Accessibility support page content. + $name = 'theme_boost_union/accessibilitysupportcontent'; + $title = get_string('accessibilitysupportcontentsetting', 'theme_boost_union', null, true); + $description = get_string('accessibilitysupportcontentsetting_desc', 'theme_boost_union', null, true); + $default = get_string('accessibilitysupportcontentdefault', 'theme_boost_union', null, true); + $setting = new admin_setting_confightmleditor($name, $title, $description, $default); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitysupportcontent', 'theme_boost_union/enableaccessibilitysupport', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Setting: Accessibility support page title. + $name = 'theme_boost_union/accessibilitysupportpagetitle'; + $title = get_string('accessibilitysupportpagetitlesetting', 'theme_boost_union', null, true); + $description = get_string('accessibilitysupportpagetitlesetting_desc', 'theme_boost_union', null, true); + $default = get_string('accessibilitysupportpagetitledefault', 'theme_boost_union', null, true); + $setting = new admin_setting_configtext($name, $title, $description, $default); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitysupportpagetitle', 'theme_boost_union/enableaccessibilitysupport', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Setting: Accessibility support page link position. + $name = 'theme_boost_union/accessibilitysupportlinkposition'; + $title = get_string('accessibilitysupportlinkpositionsetting', 'theme_boost_union', null, true); + $pageurl = theme_boost_union_get_staticpage_link('accessibilitysupport'); + $description = get_string('accessibilitysupportlinkpositionsetting_desc', 'theme_boost_union', ['url' => $pageurl], + true); + $linkpositionoption = + // Don't use string lazy loading (= false) because the string will be directly used and would produce a + // PHP warning otherwise. + [THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_NONE => + get_string('accessibilitysupportlinkpositionnone', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTNOTE => + get_string('accessibilitysupportlinkpositionfootnote', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_FOOTER => + get_string('accessibilitysupportlinkpositionfooter', 'theme_boost_union', null, false), + THEME_BOOST_UNION_SETTING_STATICPAGELINKPOSITION_BOTH => + get_string('accessibilitysupportlinkpositionboth', 'theme_boost_union', null, false), ]; + $default = 'none'; + $setting = new admin_setting_configselect($name, $title, $description, $default, $linkpositionoption); + $tab->add($setting); + $page->hide_if('theme_boost_union/accessibilitysupportlinkposition', 'theme_boost_union/enableaccessibilitysupport', 'neq', + THEME_BOOST_UNION_SETTING_SELECT_YES); + + // Setting: Enable Accessibility button. + $name = 'theme_boost_union/enableaccessibilitybutton'; + $title = get_string('enableaccessibilitybuttonsetting', 'theme_boost_union', null, true); + $description = get_string('enableaccessibilitybuttonsetting_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, + $yesnooption); + $tab->add($setting); + + // Setting: Accessibility support name. + $name = 'theme_boost_union/accessibilitysupportname'; + $title = get_string('accessibilitysupportname', 'theme_boost_union', null, true); + $description = get_string('accessibilitysupportname_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configtext($name, $title, $description, '', PARAM_NOTAGS); + $tab->add($setting); + + // Setting: Accessibility support email. + $name = 'theme_boost_union/accessibilitysupportemail'; + $title = get_string('accessibilitysupportemail', 'theme_boost_union', null, true); + $description = get_string('accessibilitysupportemail_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configtext($name, $title, $description, '', PARAM_EMAIL); + $tab->add($setting); + + // Setting: Enable anonymous send checkbox. + $name = 'theme_boost_union/enablesendanonymouscheckbox'; + $title = get_string('enablesendanonymouscheckboxsetting', 'theme_boost_union', null, true); + $description = get_string('enablesendanonymouscheckboxsetting_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_NO, + $yesnooption); + $tab->add($setting); + + // Setting: Enable checkbox for sending technical information. + $name = 'theme_boost_union/enablesendtechinfocheckbox'; + $title = get_string('enablesendtechinfocheckboxsetting', 'theme_boost_union', null, true); + $description = get_string('enablesendtechinfocheckboxsetting_desc', 'theme_boost_union', null, true); + $setting = new admin_setting_configselect($name, $title, $description, THEME_BOOST_UNION_SETTING_SELECT_YES, + $yesnooption); + $tab->add($setting); + + // Add tab to settings page. + $page->add($tab); // Create info banner tab. $tab = new admin_settingpage('theme_boost_union_infobanners_infobanner', diff --git a/templates/accessibility_support_email_body.mustache b/templates/accessibility_support_email_body.mustache new file mode 100644 index 00000000000..3ddfbacf8d4 --- /dev/null +++ b/templates/accessibility_support_email_body.mustache @@ -0,0 +1,58 @@ +{{! + 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 theme_boost_union/accessibility_site_support_email_body + + Support email email body. + + Example context (json): + { + "subject": "email subject", + "notloggedinuser": true, + "sendanonymous": false, + "sendtechinfo": true, + "name": "Sender name", + "email": "sender@mail.com", + "message": "Support request message", + "techinfo": "Moodle: 4.3.5 (Build: 20240610) (2023100905)..." + } +}} +{{#notloggedinuser}} +**{{#str}}supportmessagesentforloggedoutuser, user{{/str}}** + +{{/notloggedinuser}} +{{#sendanonymous}} +**{{#str}}accessibilitysupportsentforanonymoususer, theme_boost_union{{/str}}** + +{{/sendanonymous}} +{{#str}}name{{/str}}: {{name}} +{{#str}}email{{/str}}: {{email}} +{{#str}}subject{{/str}}: {{subject}} + +{{#str}}message{{/str}}: + +--- +{{message}} +--- + +{{#str}}accessibilitysupporttechinfo, theme_boost_union{{/str}}: +{{#sendtechinfo}} +{{techinfo}} +{{/sendtechinfo}} +{{^sendtechinfo}} +{{#str}}none{{/str}} +{{/sendtechinfo}} diff --git a/templates/accessibility_support_not_available.mustache b/templates/accessibility_support_not_available.mustache new file mode 100644 index 00000000000..341771e0411 --- /dev/null +++ b/templates/accessibility_support_not_available.mustache @@ -0,0 +1,45 @@ +{{! + 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 theme_boost_union/accessibility_support_not_available + + Content displayed on the contact site support page if attempting to submit the support form fails. + + Example context (json): + { + "supportemail": "support@mail.com", + "supportform": "" + } +}} +
+
+
{{#pix}}t/life-ring, core{{/pix}}
+
+
{{#str}}supportmessagenotsent, user{{/str}}
+ {{#supportemail}} +
+ + {{#str}}supportmessagealternative, user, {{{supportemail}}}{{/str}} + +
+ {{/supportemail}} +
+
+
+
+ {{{supportform}}} +
diff --git a/templates/footnote.mustache b/templates/footnote.mustache index d6682958b88..8ca4ef201c0 100644 --- a/templates/footnote.mustache +++ b/templates/footnote.mustache @@ -46,6 +46,12 @@ "maintenancelinkpositionfootnote": true, "maintenancelink": "https://localhost/theme/boost_union/pages/maintenance.php", "maintenancepagetitle": "Maintenance", + "accessibilitylinkpositionfootnote": true, + "accessibilitylink": "https://localhost/theme/boost_union/pages/accessibility.php", + "accessibilitypagetitle": "Declaration of accessibility", + "accessibilitysupportlinkpositionfootnote": true, + "accessibilitysupportlink": "https://localhost/theme/boost_union/pages/accessibilitysupport.php", + "accessibilitysupportpagetitle": "Accessibility support", "page1linkpositionfootnote": true, "page1link": "https://localhost/theme/boost_union/pages/page1.php", "page1pagetitle": "Generic page 1", @@ -95,6 +101,16 @@ {{ maintenancepagetitle }} {{/ maintenancelinkpositionfootnote }} + {{# accessibilitylinkpositionfootnote }} + + {{ accessibilitypagetitle }} + + {{/ accessibilitylinkpositionfootnote }} + {{# accessibilitysupportlinkpositionfootnote }} + + {{ accessibilitysupportpagetitle }} + + {{/ accessibilitysupportlinkpositionfootnote }} {{# page1linkpositionfootnote }} {{ page1pagetitle }} diff --git a/templates/theme_boost/footer.mustache b/templates/theme_boost/footer.mustache index 26c52a4e24c..af26eac1cde 100644 --- a/templates/theme_boost/footer.mustache +++ b/templates/theme_boost/footer.mustache @@ -33,6 +33,7 @@ "communication_link": "Communication room" }, "anystaticpagelinkedfromfooter": true, + "anyaccessibilitypagelinkedfromfooter": true, "imprintlinkpositionfooter": true, "imprintlink": "https://localhost/theme/boost_union/pages/imprint.php", "imprintpagetitle": "Imprint", @@ -60,6 +61,12 @@ "offerslinkpositionfooter": true, "offerslink": "https://localhost/theme/boost_union/pages/offers.php", "offerspagetitle": "Offers", + "accessibilitylinkpositionfooter": true, + "accessibilitylink": "https://localhost/theme/boost_union/pages/accessibility.php", + "accessibilitypagetitle": "Declaration of accessibility", + "accessibilitysupportlinkpositionfooter": true, + "accessibilitysupportlink": "https://localhost/theme/boost_union/pages/accessibilitysupport.php", + "accessibilitysupporttitle": "Accessibility support", "page1linkpositionfooter": true, "page1link": "https://localhost/theme/boost_union/pages/page1.php", "page1pagetitle": "Generic page 1", @@ -82,6 +89,8 @@ * Added the possibility to show the maintenance page link. * Added the possibility to show the about us page link. * Added the possibility to show the offers page link. + * Added the possibility to show the accessibility page link. + * Added the possibility to show the accessibility support page link. * Added the possibility to show the generic page 1 link. * Added the possibility to show the generic page 2 link. * Added the possibility to show the generic page 3 link. @@ -112,6 +121,13 @@ {{#pix}}e/question, core{{/pix}} {{/footerbutton }} +
+ {{#accessibilitybutton}} + + + + {{/accessibilitybutton}} +
{{#footerbutton }} {{/anystaticpagelinkedfromfooter}} + {{#anyaccessibilitypagelinkedfromfooter}} + + {{/anyaccessibilitypagelinkedfromfooter}} {{#footershowlogininfo}}