From 5034f0a12bc06d66a1b6130bf0059a1ab43e9b16 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 12 Sep 2019 14:19:11 +0800 Subject: [PATCH 1/2] MDL-66550 theme: Wrap JS calls in pendingJS --- lib/outputfragmentrequirementslib.php | 4 +++- lib/outputrequirementslib.php | 18 ++++++++++++------ lib/tests/outputrequirementslib_test.php | 11 ++++++++--- theme/boost/amd/build/aria.min.js | 2 +- theme/boost/amd/build/aria.min.js.map | 2 +- theme/boost/amd/build/loader.min.js | 2 +- theme/boost/amd/build/loader.min.js.map | 2 +- theme/boost/amd/src/aria.js | 3 ++- theme/boost/amd/src/loader.js | 2 ++ theme/boost/templates/columns1.mustache | 5 ++++- theme/boost/templates/columns2.mustache | 7 ++++++- theme/boost/templates/embedded.mustache | 5 ++++- theme/boost/templates/login.mustache | 5 ++++- theme/boost/templates/maintenance.mustache | 5 ++++- theme/boost/templates/secure.mustache | 5 ++++- theme/classic/templates/columns.mustache | 6 ++++-- theme/classic/templates/contentonly.mustache | 5 ++++- theme/classic/templates/secure.mustache | 5 ++++- 18 files changed, 69 insertions(+), 25 deletions(-) diff --git a/lib/outputfragmentrequirementslib.php b/lib/outputfragmentrequirementslib.php index 0ae13fbb789..da753ef3332 100644 --- a/lib/outputfragmentrequirementslib.php +++ b/lib/outputfragmentrequirementslib.php @@ -57,8 +57,10 @@ class fragment_requirements_manager extends page_requirements_manager { $output = ''; // First include must be to a module with no dependencies, this prevents multiple requests. - $prefix = "require(['core/first'], function() {\n"; + $prefix = 'M.util.js_pending("core/first");'; + $prefix .= "require(['core/first'], function() {\n"; $suffix = "\n});"; + $suffix .= 'M.util.js_complete("core/first");'; $output .= html_writer::script($prefix . implode(";\n", $this->amdjscode) . $suffix); return $output; } diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php index 3ecdb37679e..0b7d01addb4 100644 --- a/lib/outputrequirementslib.php +++ b/lib/outputrequirementslib.php @@ -1038,7 +1038,9 @@ class page_requirements_manager { $component = clean_param($component, PARAM_COMPONENT); $module = clean_param($module, PARAM_ALPHANUMEXT); + $modname = "{$component}/{$module}"; + $functioncode = []; if ($func !== null) { $func = clean_param($func, PARAM_ALPHANUMEXT); @@ -1057,12 +1059,14 @@ class page_requirements_manager { } } - $js = 'require(["' . $component . '/' . $module . '"], function(amd) { amd.' . $func . '(' . $strparams . '); });'; - - } else { - $js = 'require(["' . $component . '/' . $module . '"]);'; + $functioncode[] = "amd.{$func}({$strparams});"; } + $functioncode[] = "M.util.js_complete('{$modname}');"; + + $initcode = implode(' ', $functioncode); + $js = "M.util.js_pending('{$modname}'); require(['{$modname}'], function(amd) {{$initcode}});"; + $this->js_amd_inline($js); } @@ -1384,8 +1388,10 @@ class page_requirements_manager { } // First include must be to a module with no dependencies, this prevents multiple requests. - $prefix = "require(['core/first'], function() {\n"; - $suffix = "\n});"; + $prefix = 'M.util.js_pending("core/first");'; + $prefix .= "require(['core/first'], function() {\n"; + $suffix = 'M.util.js_complete("core/first");'; + $suffix .= "\n});"; $output .= html_writer::script($prefix . implode(";\n", $this->amdjscode) . $suffix); return $output; } diff --git a/lib/tests/outputrequirementslib_test.php b/lib/tests/outputrequirementslib_test.php index 58680786d24..d1ac6895011 100644 --- a/lib/tests/outputrequirementslib_test.php +++ b/lib/tests/outputrequirementslib_test.php @@ -125,8 +125,13 @@ class core_outputrequirementslib_testcase extends advanced_testcase { $html = $page->requires->get_end_code(); - $this->assertContains('require(["theme_foobar/lightbox"]);', $html); - $this->assertContains('require(["theme_foobar/demo_one"], function(amd) { amd.init(); });', $html); - $this->assertContains('require(["theme_foobar/demo_two"], function(amd) { amd.init("foo", "baz", [42,"xyz"]); });', $html); + $modname = 'theme_foobar/lightbox'; + $this->assertContains("M.util.js_pending('{$modname}'); require(['{$modname}'], function(amd) {M.util.js_complete('{$modname}');});", $html); + + $modname = 'theme_foobar/demo_one'; + $this->assertContains("M.util.js_pending('{$modname}'); require(['{$modname}'], function(amd) {amd.init(); M.util.js_complete('{$modname}');});", $html); + + $modname = 'theme_foobar/demo_two'; + $this->assertContains("M.util.js_pending('{$modname}'); require(['{$modname}'], function(amd) {amd.init(\"foo\", \"baz\", [42,\"xyz\"]); M.util.js_complete('{$modname}');});", $html); } } diff --git a/theme/boost/amd/build/aria.min.js b/theme/boost/amd/build/aria.min.js index c02d5ecb5e0..c1d51e87b3f 100644 --- a/theme/boost/amd/build/aria.min.js +++ b/theme/boost/amd/build/aria.min.js @@ -1,2 +1,2 @@ -define ("theme_boost/aria",["jquery","core/pending"],function(a,b){return{init:function init(){var c=!1,d=function(){c=!0},e=function(){var a=c;c=!1;return a};a("[data-toggle=\"dropdown\"]").keydown(function(b){var c=b.which||b.keyCode,e;if(38==c){d()}if(27==c){e=a(b.target).attr("aria-expanded");b.preventDefault();if("false"==e){a(b.target).click()}}if(32==c||13==c){b.preventDefault();a(b.target).click()}});var f=function(c){var d=function(b){a(this).focus();b.resolve()}.bind(c);setTimeout(d,50,new b("core/aria:delayed-focus"))};a(".dropdown").on("shown.bs.dropdown",function(b){var c=a(b.target).find("[role=\"menu\"]"),d=!1,g=!1;if(c){d=a(c).find("[role=\"menuitem\"]")}if(d&&0.\n\n/**\n * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/pending'], function($, Pending) {\n return {\n init: function() {\n // Drop downs from bootstrap don't support keyboard accessibility by default.\n var focusEnd = false,\n setFocusEnd = function() {\n focusEnd = true;\n },\n getFocusEnd = function() {\n var result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for \"up\" keyboard control.\n $('[data-toggle=\"dropdown\"]').keydown(function(e) {\n var trigger = e.which || e.keyCode,\n expanded;\n\n // Up key opens the menu at the end.\n if (trigger == 38) {\n // Focus the end of the menu, not the beginning.\n setFocusEnd();\n }\n\n // Escape key only closes the menu, it doesn't open it.\n if (trigger == 27) {\n expanded = $(e.target).attr('aria-expanded');\n e.preventDefault();\n if (expanded == \"false\") {\n $(e.target).click();\n }\n }\n\n // Space key or Enter key opens the menu.\n if (trigger == 32 || trigger == 13) {\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n $(e.target).click();\n }\n });\n\n // Special handling for navigation keys when menu is open.\n var shiftFocus = function(element) {\n var delayedFocus = function(pendingPromise) {\n $(this).focus();\n pendingPromise.resolve();\n }.bind(element);\n setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));\n };\n\n $('.dropdown').on('shown.bs.dropdown', function(e) {\n // We need to focus on the first menuitem.\n var menu = $(e.target).find('[role=\"menu\"]'),\n menuItems = false,\n foundMenuItem = false;\n\n if (menu) {\n menuItems = $(menu).find('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n });\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n $('.dropdown [role=\"menu\"] [role=\"menuitem\"]').keypress(function(e) {\n var trigger = String.fromCharCode(e.which || e.keyCode),\n menu = $(e.target).closest('[role=\"menu\"]'),\n i = 0,\n menuItems = false,\n item,\n itemText;\n\n if (!menu) {\n return;\n }\n menuItems = $(menu).find('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n trigger = trigger.toLowerCase();\n for (i = 0; i < menuItems.length; i++) {\n item = $(menuItems[i]);\n itemText = item.text().trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n $('.dropdown [role=\"menu\"] [role=\"menuitem\"]').keydown(function(e) {\n var trigger = e.which || e.keyCode,\n next = false,\n menu = $(e.target).closest('[role=\"menu\"]'),\n i = 0,\n menuItems = false;\n if (!menu) {\n return;\n }\n menuItems = $(menu).find('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == 40) {\n for (i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n\n } else if (trigger == 38) {\n // Up key.\n for (i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n\n } else if (trigger == 36) {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == 35) {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n });\n $('.dropdown').on('hidden.bs.dropdown', function(e) {\n // We need to focus on the menu trigger.\n var trigger = $(e.target).find('[data-toggle=\"dropdown\"]');\n if (trigger) {\n shiftFocus(trigger);\n }\n });\n\n // After page load, focus on any element with special autofocus attribute.\n $(function() {\n window.setTimeout(function(pendingPromise) {\n var alerts = $('[role=\"alert\"][data-aria-autofocus=\"true\"]');\n if (alerts.length > 0) {\n $(alerts[0]).attr('tabindex', '0');\n $(alerts[0]).focus();\n }\n pendingPromise.resolve();\n }, 300, new Pending('core/aria:delayed-focus'));\n });\n }\n };\n});\n"],"file":"aria.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/aria.js"],"names":["define","$","Pending","init","focusEnd","setFocusEnd","getFocusEnd","result","keydown","e","trigger","which","keyCode","expanded","target","attr","preventDefault","click","shiftFocus","element","delayedFocus","pendingPromise","focus","resolve","bind","setTimeout","on","menu","find","menuItems","foundMenuItem","length","keypress","String","fromCharCode","closest","i","item","itemText","toLowerCase","text","trim","indexOf","next","delayedFocusPromise","window","alerts"],"mappings":"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","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 * Enhancements to Bootstrap components for accessibility.\n *\n * @module theme_boost/aria\n * @copyright 2018 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/pending'], function($, Pending) {\n return {\n init: function() {\n // Drop downs from bootstrap don't support keyboard accessibility by default.\n var focusEnd = false,\n setFocusEnd = function() {\n focusEnd = true;\n },\n getFocusEnd = function() {\n var result = focusEnd;\n focusEnd = false;\n return result;\n };\n\n // Special handling for \"up\" keyboard control.\n $('[data-toggle=\"dropdown\"]').keydown(function(e) {\n var trigger = e.which || e.keyCode,\n expanded;\n\n // Up key opens the menu at the end.\n if (trigger == 38) {\n // Focus the end of the menu, not the beginning.\n setFocusEnd();\n }\n\n // Escape key only closes the menu, it doesn't open it.\n if (trigger == 27) {\n expanded = $(e.target).attr('aria-expanded');\n e.preventDefault();\n if (expanded == \"false\") {\n $(e.target).click();\n }\n }\n\n // Space key or Enter key opens the menu.\n if (trigger == 32 || trigger == 13) {\n // Cancel random scroll.\n e.preventDefault();\n // Open the menu instead.\n $(e.target).click();\n }\n });\n\n // Special handling for navigation keys when menu is open.\n var shiftFocus = function(element) {\n var delayedFocus = function(pendingPromise) {\n $(this).focus();\n pendingPromise.resolve();\n }.bind(element);\n setTimeout(delayedFocus, 50, new Pending('core/aria:delayed-focus'));\n };\n\n $('.dropdown').on('shown.bs.dropdown', function(e) {\n // We need to focus on the first menuitem.\n var menu = $(e.target).find('[role=\"menu\"]'),\n menuItems = false,\n foundMenuItem = false;\n\n if (menu) {\n menuItems = $(menu).find('[role=\"menuitem\"]');\n }\n if (menuItems && menuItems.length > 0) {\n if (getFocusEnd()) {\n foundMenuItem = menuItems[menuItems.length - 1];\n } else {\n // The first menu entry, pretty reasonable.\n foundMenuItem = menuItems[0];\n }\n }\n if (foundMenuItem) {\n shiftFocus(foundMenuItem);\n }\n });\n // Search for menu items by finding the first item that has\n // text starting with the typed character (case insensitive).\n $('.dropdown [role=\"menu\"] [role=\"menuitem\"]').keypress(function(e) {\n var trigger = String.fromCharCode(e.which || e.keyCode),\n menu = $(e.target).closest('[role=\"menu\"]'),\n i = 0,\n menuItems = false,\n item,\n itemText;\n\n if (!menu) {\n return;\n }\n menuItems = $(menu).find('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n\n trigger = trigger.toLowerCase();\n for (i = 0; i < menuItems.length; i++) {\n item = $(menuItems[i]);\n itemText = item.text().trim().toLowerCase();\n if (itemText.indexOf(trigger) == 0) {\n shiftFocus(item);\n break;\n }\n }\n });\n\n // Keyboard navigation for arrow keys, home and end keys.\n $('.dropdown [role=\"menu\"] [role=\"menuitem\"]').keydown(function(e) {\n var trigger = e.which || e.keyCode,\n next = false,\n menu = $(e.target).closest('[role=\"menu\"]'),\n i = 0,\n menuItems = false;\n if (!menu) {\n return;\n }\n menuItems = $(menu).find('[role=\"menuitem\"]');\n if (!menuItems) {\n return;\n }\n // Down key.\n if (trigger == 40) {\n for (i = 0; i < menuItems.length - 1; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i + 1];\n break;\n }\n }\n if (!next) {\n // Wrap to first item.\n next = menuItems[0];\n }\n\n } else if (trigger == 38) {\n // Up key.\n for (i = 1; i < menuItems.length; i++) {\n if (menuItems[i] == e.target) {\n next = menuItems[i - 1];\n break;\n }\n }\n if (!next) {\n // Wrap to last item.\n next = menuItems[menuItems.length - 1];\n }\n\n } else if (trigger == 36) {\n // Home key.\n next = menuItems[0];\n\n } else if (trigger == 35) {\n // End key.\n next = menuItems[menuItems.length - 1];\n }\n // Variable next is set if we do want to act on the keypress.\n if (next) {\n e.preventDefault();\n shiftFocus(next);\n }\n return;\n });\n $('.dropdown').on('hidden.bs.dropdown', function(e) {\n // We need to focus on the menu trigger.\n var trigger = $(e.target).find('[data-toggle=\"dropdown\"]');\n if (trigger) {\n shiftFocus(trigger);\n }\n });\n\n // After page load, focus on any element with special autofocus attribute.\n var delayedFocusPromise = new Pending('core/aria:delayed-focus');\n $(function() {\n window.setTimeout(function(pendingPromise) {\n var alerts = $('[role=\"alert\"][data-aria-autofocus=\"true\"]');\n if (alerts.length > 0) {\n $(alerts[0]).attr('tabindex', '0');\n $(alerts[0]).focus();\n }\n pendingPromise.resolve();\n }, 300, delayedFocusPromise);\n });\n }\n };\n});\n"],"file":"aria.min.js"} \ No newline at end of file diff --git a/theme/boost/amd/build/loader.min.js b/theme/boost/amd/build/loader.min.js index 33e09e43262..51909c97aae 100644 --- a/theme/boost/amd/build/loader.min.js +++ b/theme/boost/amd/build/loader.min.js @@ -1,2 +1,2 @@ -define ("theme_boost/loader",["jquery","./tether","core/event"],function(a,b,c){window.jQuery=a;window.Tether=b;require(["theme_boost/aria","theme_boost/pending","theme_boost/util","theme_boost/alert","theme_boost/button","theme_boost/carousel","theme_boost/collapse","theme_boost/dropdown","theme_boost/modal","theme_boost/scrollspy","theme_boost/tab","theme_boost/tooltip","theme_boost/popover"],function(b){a("body").popover({trigger:"focus",selector:"[data-toggle=popover][data-trigger!=hover]"});a("html").popover({container:"body",selector:"[data-toggle=popover][data-trigger=hover]",trigger:"hover",delay:{hide:500}});a.fn.dropdown.Constructor.Default.flip=!1;a("a[data-toggle=\"tab\"]").on("shown.bs.tab",function(b){var c=a(b.target).attr("href");if(history.replaceState){history.replaceState(null,null,c)}else{location.hash=c}});var d=window.location.hash;if(d){a(".nav-link[href=\""+d+"\"]").tab("show")}c.getLegacyEvents().done(function(b){a(document).on(b.FILTER_CONTENT_UPDATED,function(){a("body").popover({selector:"[data-toggle=\"popover\"]",trigger:"focus"})})});b.init()});return{}}); +define ("theme_boost/loader",["jquery","./tether","core/event"],function(a,b,c){window.jQuery=a;window.Tether=b;M.util.js_pending("theme_boost/loader:children");require(["theme_boost/aria","theme_boost/pending","theme_boost/util","theme_boost/alert","theme_boost/button","theme_boost/carousel","theme_boost/collapse","theme_boost/dropdown","theme_boost/modal","theme_boost/scrollspy","theme_boost/tab","theme_boost/tooltip","theme_boost/popover"],function(b){a("body").popover({trigger:"focus",selector:"[data-toggle=popover][data-trigger!=hover]"});a("html").popover({container:"body",selector:"[data-toggle=popover][data-trigger=hover]",trigger:"hover",delay:{hide:500}});a.fn.dropdown.Constructor.Default.flip=!1;a("a[data-toggle=\"tab\"]").on("shown.bs.tab",function(b){var c=a(b.target).attr("href");if(history.replaceState){history.replaceState(null,null,c)}else{location.hash=c}});var d=window.location.hash;if(d){a(".nav-link[href=\""+d+"\"]").tab("show")}c.getLegacyEvents().done(function(b){a(document).on(b.FILTER_CONTENT_UPDATED,function(){a("body").popover({selector:"[data-toggle=\"popover\"]",trigger:"focus"})})});b.init();M.util.js_complete("theme_boost/loader:children")});return{}}); //# sourceMappingURL=loader.min.js.map diff --git a/theme/boost/amd/build/loader.min.js.map b/theme/boost/amd/build/loader.min.js.map index b090f5bb5d6..94e93e44417 100644 --- a/theme/boost/amd/build/loader.min.js.map +++ b/theme/boost/amd/build/loader.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/loader.js"],"names":["define","jQuery","Tether","Event","window","require","Aria","popover","trigger","selector","container","delay","hide","fn","dropdown","Constructor","Default","flip","on","e","hash","target","attr","history","replaceState","location","tab","getLegacyEvents","done","events","document","FILTER_CONTENT_UPDATED","init"],"mappings":"AAyBAA,OAAM,sBAAC,CAAC,QAAD,CAAW,UAAX,CAAuB,YAAvB,CAAD,CAAuC,SAASC,CAAT,CAAiBC,CAAjB,CAAyBC,CAAzB,CAAgC,CAEzEC,MAAM,CAACH,MAAP,CAAgBA,CAAhB,CACAG,MAAM,CAACF,MAAP,CAAgBA,CAAhB,CAEAG,OAAO,CAAC,CAAC,kBAAD,CACA,qBADA,CAEA,kBAFA,CAGA,mBAHA,CAIA,oBAJA,CAKA,sBALA,CAMA,sBANA,CAOA,sBAPA,CAQA,mBARA,CASA,uBATA,CAUA,iBAVA,CAWA,qBAXA,CAYA,qBAZA,CAAD,CAaC,SAASC,CAAT,CAAe,CAGnBL,CAAM,CAAC,MAAD,CAAN,CAAeM,OAAf,CAAuB,CACnBC,OAAO,CAAE,OADU,CAEnBC,QAAQ,CAAE,4CAFS,CAAvB,EAKAR,CAAM,CAAC,MAAD,CAAN,CAAeM,OAAf,CAAuB,CACnBG,SAAS,CAAE,MADQ,CAEnBD,QAAQ,CAAE,2CAFS,CAGnBD,OAAO,CAAE,OAHU,CAInBG,KAAK,CAAE,CACHC,IAAI,CAAE,GADH,CAJY,CAAvB,EAUAX,CAAM,CAACY,EAAP,CAAUC,QAAV,CAAmBC,WAAnB,CAA+BC,OAA/B,CAAuCC,IAAvC,IAEAhB,CAAM,CAAC,wBAAD,CAAN,CAA+BiB,EAA/B,CAAkC,cAAlC,CAAkD,SAASC,CAAT,CAAY,CAC1D,GAAIC,CAAAA,CAAI,CAAGnB,CAAM,CAACkB,CAAC,CAACE,MAAH,CAAN,CAAiBC,IAAjB,CAAsB,MAAtB,CAAX,CACA,GAAIC,OAAO,CAACC,YAAZ,CAA0B,CACtBD,OAAO,CAACC,YAAR,CAAqB,IAArB,CAA2B,IAA3B,CAAiCJ,CAAjC,CACH,CAFD,IAEO,CACHK,QAAQ,CAACL,IAAT,CAAgBA,CACnB,CACJ,CAPD,EASA,GAAIA,CAAAA,CAAI,CAAGhB,MAAM,CAACqB,QAAP,CAAgBL,IAA3B,CACA,GAAIA,CAAJ,CAAU,CACPnB,CAAM,CAAC,oBAAqBmB,CAArB,CAA4B,KAA7B,CAAN,CAAyCM,GAAzC,CAA6C,MAA7C,CACF,CAGDvB,CAAK,CAACwB,eAAN,GAAwBC,IAAxB,CAA6B,SAASC,CAAT,CAAiB,CAC1C5B,CAAM,CAAC6B,QAAD,CAAN,CAAiBZ,EAAjB,CAAoBW,CAAM,CAACE,sBAA3B,CAAmD,UAAW,CAC1D9B,CAAM,CAAC,MAAD,CAAN,CAAeM,OAAf,CAAuB,CACnBE,QAAQ,CAAE,2BADS,CAEnBD,OAAO,CAAE,OAFU,CAAvB,CAKH,CAND,CAOH,CARD,EAUAF,CAAI,CAAC0B,IAAL,EACH,CA3DM,CAAP,CA8DA,MAAO,EACV,CApEK,CAAN","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 * Template renderer for Moodle. Load and render Moodle templates with Mustache.\n *\n * @module core/templates\n * @package core\n * @class templates\n * @copyright 2015 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 2.9\n */\ndefine(['jquery', './tether', 'core/event'], function(jQuery, Tether, Event) {\n\n window.jQuery = jQuery;\n window.Tether = Tether;\n\n require(['theme_boost/aria',\n 'theme_boost/pending',\n 'theme_boost/util',\n 'theme_boost/alert',\n 'theme_boost/button',\n 'theme_boost/carousel',\n 'theme_boost/collapse',\n 'theme_boost/dropdown',\n 'theme_boost/modal',\n 'theme_boost/scrollspy',\n 'theme_boost/tab',\n 'theme_boost/tooltip',\n 'theme_boost/popover'],\n function(Aria) {\n\n // We do twice because: https://github.com/twbs/bootstrap/issues/10547\n jQuery('body').popover({\n trigger: 'focus',\n selector: \"[data-toggle=popover][data-trigger!=hover]\"\n });\n\n jQuery(\"html\").popover({\n container: \"body\",\n selector: \"[data-toggle=popover][data-trigger=hover]\",\n trigger: \"hover\",\n delay: {\n hide: 500\n }\n });\n\n // Disables flipping the dropdowns up and getting hidden behind the navbar.\n jQuery.fn.dropdown.Constructor.Default.flip = false;\n\n jQuery('a[data-toggle=\"tab\"]').on('shown.bs.tab', function(e) {\n var hash = jQuery(e.target).attr('href');\n if (history.replaceState) {\n history.replaceState(null, null, hash);\n } else {\n location.hash = hash;\n }\n });\n\n var hash = window.location.hash;\n if (hash) {\n jQuery('.nav-link[href=\"' + hash + '\"]').tab('show');\n }\n\n // We need to call popover automatically if nodes are added to the page later.\n Event.getLegacyEvents().done(function(events) {\n jQuery(document).on(events.FILTER_CONTENT_UPDATED, function() {\n jQuery('body').popover({\n selector: '[data-toggle=\"popover\"]',\n trigger: 'focus'\n });\n\n });\n });\n\n Aria.init();\n });\n\n\n return {};\n});\n"],"file":"loader.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/loader.js"],"names":["define","jQuery","Tether","Event","window","M","util","js_pending","require","Aria","popover","trigger","selector","container","delay","hide","fn","dropdown","Constructor","Default","flip","on","e","hash","target","attr","history","replaceState","location","tab","getLegacyEvents","done","events","document","FILTER_CONTENT_UPDATED","init","js_complete"],"mappings":"AAyBAA,OAAM,sBAAC,CAAC,QAAD,CAAW,UAAX,CAAuB,YAAvB,CAAD,CAAuC,SAASC,CAAT,CAAiBC,CAAjB,CAAyBC,CAAzB,CAAgC,CAEzEC,MAAM,CAACH,MAAP,CAAgBA,CAAhB,CACAG,MAAM,CAACF,MAAP,CAAgBA,CAAhB,CACAG,CAAC,CAACC,IAAF,CAAOC,UAAP,CAAkB,6BAAlB,EAEAC,OAAO,CAAC,CAAC,kBAAD,CACA,qBADA,CAEA,kBAFA,CAGA,mBAHA,CAIA,oBAJA,CAKA,sBALA,CAMA,sBANA,CAOA,sBAPA,CAQA,mBARA,CASA,uBATA,CAUA,iBAVA,CAWA,qBAXA,CAYA,qBAZA,CAAD,CAaC,SAASC,CAAT,CAAe,CAGnBR,CAAM,CAAC,MAAD,CAAN,CAAeS,OAAf,CAAuB,CACnBC,OAAO,CAAE,OADU,CAEnBC,QAAQ,CAAE,4CAFS,CAAvB,EAKAX,CAAM,CAAC,MAAD,CAAN,CAAeS,OAAf,CAAuB,CACnBG,SAAS,CAAE,MADQ,CAEnBD,QAAQ,CAAE,2CAFS,CAGnBD,OAAO,CAAE,OAHU,CAInBG,KAAK,CAAE,CACHC,IAAI,CAAE,GADH,CAJY,CAAvB,EAUAd,CAAM,CAACe,EAAP,CAAUC,QAAV,CAAmBC,WAAnB,CAA+BC,OAA/B,CAAuCC,IAAvC,IAEAnB,CAAM,CAAC,wBAAD,CAAN,CAA+BoB,EAA/B,CAAkC,cAAlC,CAAkD,SAASC,CAAT,CAAY,CAC1D,GAAIC,CAAAA,CAAI,CAAGtB,CAAM,CAACqB,CAAC,CAACE,MAAH,CAAN,CAAiBC,IAAjB,CAAsB,MAAtB,CAAX,CACA,GAAIC,OAAO,CAACC,YAAZ,CAA0B,CACtBD,OAAO,CAACC,YAAR,CAAqB,IAArB,CAA2B,IAA3B,CAAiCJ,CAAjC,CACH,CAFD,IAEO,CACHK,QAAQ,CAACL,IAAT,CAAgBA,CACnB,CACJ,CAPD,EASA,GAAIA,CAAAA,CAAI,CAAGnB,MAAM,CAACwB,QAAP,CAAgBL,IAA3B,CACA,GAAIA,CAAJ,CAAU,CACPtB,CAAM,CAAC,oBAAqBsB,CAArB,CAA4B,KAA7B,CAAN,CAAyCM,GAAzC,CAA6C,MAA7C,CACF,CAGD1B,CAAK,CAAC2B,eAAN,GAAwBC,IAAxB,CAA6B,SAASC,CAAT,CAAiB,CAC1C/B,CAAM,CAACgC,QAAD,CAAN,CAAiBZ,EAAjB,CAAoBW,CAAM,CAACE,sBAA3B,CAAmD,UAAW,CAC1DjC,CAAM,CAAC,MAAD,CAAN,CAAeS,OAAf,CAAuB,CACnBE,QAAQ,CAAE,2BADS,CAEnBD,OAAO,CAAE,OAFU,CAAvB,CAKH,CAND,CAOH,CARD,EAUAF,CAAI,CAAC0B,IAAL,GACA9B,CAAC,CAACC,IAAF,CAAO8B,WAAP,CAAmB,6BAAnB,CACH,CA5DM,CAAP,CA+DA,MAAO,EACV,CAtEK,CAAN","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 * Template renderer for Moodle. Load and render Moodle templates with Mustache.\n *\n * @module core/templates\n * @package core\n * @class templates\n * @copyright 2015 Damyon Wiese \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 2.9\n */\ndefine(['jquery', './tether', 'core/event'], function(jQuery, Tether, Event) {\n\n window.jQuery = jQuery;\n window.Tether = Tether;\n M.util.js_pending('theme_boost/loader:children');\n\n require(['theme_boost/aria',\n 'theme_boost/pending',\n 'theme_boost/util',\n 'theme_boost/alert',\n 'theme_boost/button',\n 'theme_boost/carousel',\n 'theme_boost/collapse',\n 'theme_boost/dropdown',\n 'theme_boost/modal',\n 'theme_boost/scrollspy',\n 'theme_boost/tab',\n 'theme_boost/tooltip',\n 'theme_boost/popover'],\n function(Aria) {\n\n // We do twice because: https://github.com/twbs/bootstrap/issues/10547\n jQuery('body').popover({\n trigger: 'focus',\n selector: \"[data-toggle=popover][data-trigger!=hover]\"\n });\n\n jQuery(\"html\").popover({\n container: \"body\",\n selector: \"[data-toggle=popover][data-trigger=hover]\",\n trigger: \"hover\",\n delay: {\n hide: 500\n }\n });\n\n // Disables flipping the dropdowns up and getting hidden behind the navbar.\n jQuery.fn.dropdown.Constructor.Default.flip = false;\n\n jQuery('a[data-toggle=\"tab\"]').on('shown.bs.tab', function(e) {\n var hash = jQuery(e.target).attr('href');\n if (history.replaceState) {\n history.replaceState(null, null, hash);\n } else {\n location.hash = hash;\n }\n });\n\n var hash = window.location.hash;\n if (hash) {\n jQuery('.nav-link[href=\"' + hash + '\"]').tab('show');\n }\n\n // We need to call popover automatically if nodes are added to the page later.\n Event.getLegacyEvents().done(function(events) {\n jQuery(document).on(events.FILTER_CONTENT_UPDATED, function() {\n jQuery('body').popover({\n selector: '[data-toggle=\"popover\"]',\n trigger: 'focus'\n });\n\n });\n });\n\n Aria.init();\n M.util.js_complete('theme_boost/loader:children');\n });\n\n\n return {};\n});\n"],"file":"loader.min.js"} \ No newline at end of file diff --git a/theme/boost/amd/src/aria.js b/theme/boost/amd/src/aria.js index 3bcff10b910..360ffa21500 100644 --- a/theme/boost/amd/src/aria.js +++ b/theme/boost/amd/src/aria.js @@ -186,6 +186,7 @@ define(['jquery', 'core/pending'], function($, Pending) { }); // After page load, focus on any element with special autofocus attribute. + var delayedFocusPromise = new Pending('core/aria:delayed-focus'); $(function() { window.setTimeout(function(pendingPromise) { var alerts = $('[role="alert"][data-aria-autofocus="true"]'); @@ -194,7 +195,7 @@ define(['jquery', 'core/pending'], function($, Pending) { $(alerts[0]).focus(); } pendingPromise.resolve(); - }, 300, new Pending('core/aria:delayed-focus')); + }, 300, delayedFocusPromise); }); } }; diff --git a/theme/boost/amd/src/loader.js b/theme/boost/amd/src/loader.js index bb29acb0c60..17e94770007 100644 --- a/theme/boost/amd/src/loader.js +++ b/theme/boost/amd/src/loader.js @@ -27,6 +27,7 @@ define(['jquery', './tether', 'core/event'], function(jQuery, Tether, Event) { window.jQuery = jQuery; window.Tether = Tether; + M.util.js_pending('theme_boost/loader:children'); require(['theme_boost/aria', 'theme_boost/pending', @@ -87,6 +88,7 @@ define(['jquery', './tether', 'core/event'], function(jQuery, Tether, Event) { }); Aria.init(); + M.util.js_complete('theme_boost/loader:children'); }); diff --git a/theme/boost/templates/columns1.mustache b/theme/boost/templates/columns1.mustache index 49ed3ba1e9c..e64e37bf8f2 100644 --- a/theme/boost/templates/columns1.mustache +++ b/theme/boost/templates/columns1.mustache @@ -64,5 +64,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/boost/templates/columns2.mustache b/theme/boost/templates/columns2.mustache index d0425d39965..9953d8eadb8 100644 --- a/theme/boost/templates/columns2.mustache +++ b/theme/boost/templates/columns2.mustache @@ -95,8 +95,13 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); +M.util.js_pending('theme_boost/drawer'); require(['theme_boost/drawer'], function(mod) { mod.init(); + M.util.js_complete('theme_boost/drawer'); }); {{/js}} diff --git a/theme/boost/templates/embedded.mustache b/theme/boost/templates/embedded.mustache index e38dab69ffc..ce62a560154 100644 --- a/theme/boost/templates/embedded.mustache +++ b/theme/boost/templates/embedded.mustache @@ -53,5 +53,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/boost/templates/login.mustache b/theme/boost/templates/login.mustache index f44017ddb6c..554a5c0b234 100644 --- a/theme/boost/templates/login.mustache +++ b/theme/boost/templates/login.mustache @@ -67,5 +67,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/boost/templates/maintenance.mustache b/theme/boost/templates/maintenance.mustache index 0330892b031..481314b2d2b 100644 --- a/theme/boost/templates/maintenance.mustache +++ b/theme/boost/templates/maintenance.mustache @@ -73,5 +73,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/boost/templates/secure.mustache b/theme/boost/templates/secure.mustache index a6ceaba4c8d..a83cb82d1a1 100644 --- a/theme/boost/templates/secure.mustache +++ b/theme/boost/templates/secure.mustache @@ -87,5 +87,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/classic/templates/columns.mustache b/theme/classic/templates/columns.mustache index 3d2f6b072a6..9c48f24a9c6 100644 --- a/theme/classic/templates/columns.mustache +++ b/theme/classic/templates/columns.mustache @@ -96,6 +96,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} - diff --git a/theme/classic/templates/contentonly.mustache b/theme/classic/templates/contentonly.mustache index 1d1ce7ac6b5..2ba1a959c18 100644 --- a/theme/classic/templates/contentonly.mustache +++ b/theme/classic/templates/contentonly.mustache @@ -68,5 +68,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} diff --git a/theme/classic/templates/secure.mustache b/theme/classic/templates/secure.mustache index 8c5dc54333a..0aeceec60db 100644 --- a/theme/classic/templates/secure.mustache +++ b/theme/classic/templates/secure.mustache @@ -106,5 +106,8 @@ {{#js}} -require(['theme_boost/loader']); +M.util.js_pending('theme_boost/loader'); +require(['theme_boost/loader'], function() { + M.util.js_complete('theme_boost/loader'); +}); {{/js}} From 419b269c9e7cae584e520bc8511a3ed484221d8b Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Thu, 12 Sep 2019 14:18:36 +0800 Subject: [PATCH 2/2] MDL-66550 admin: The execute wrapper MUST be used in behat --- admin/tests/behat/behat_admin.php | 27 ++------------- .../behat/behat_theme_classic_behat_admin.php | 34 +++---------------- 2 files changed, 7 insertions(+), 54 deletions(-) diff --git a/admin/tests/behat/behat_admin.php b/admin/tests/behat/behat_admin.php index 87a00b6cdad..af027dec4c8 100644 --- a/admin/tests/behat/behat_admin.php +++ b/admin/tests/behat/behat_admin.php @@ -48,13 +48,11 @@ class behat_admin extends behat_base { * @param TableNode $table */ public function i_set_the_following_administration_settings_values(TableNode $table) { - if (!$data = $table->getRowsHash()) { return; } foreach ($data as $label => $value) { - $this->execute('behat_navigation::i_select_from_flat_navigation_drawer', [get_string('administrationsite')]); // Search by label. @@ -76,38 +74,17 @@ class behat_admin extends behat_base { "@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]"; $fieldnode = $this->find('xpath', $fieldxpath, $exception); - $formfieldtypenode = $this->find('xpath', $fieldxpath . - "/ancestor::div[contains(concat(' ', @class, ' '), ' form-setting ')]" . - "/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div"); - } catch (ElementNotFoundException $e) { - // Multi element settings, interacting only the first one. $fieldxpath = "//*[label[contains(., $label)]|span[contains(., $label)]]" . "/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" . "/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" . "/descendant::*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]"; - $fieldnode = $this->find('xpath', $fieldxpath); - - // It is the same one that contains the type. - $formfieldtypenode = $fieldnode; } - // Getting the class which contains the field type. - $classes = explode(' ', $formfieldtypenode->getAttribute('class')); - $type = false; - foreach ($classes as $class) { - if (substr($class, 0, 5) == 'form-') { - $type = substr($class, 5); - } - } - - // Instantiating the appropiate field type. - $field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession()); - $field->set_value($value); - - $this->find_button(get_string('savechanges'))->press(); + $this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]); + $this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']); } } diff --git a/theme/classic/tests/behat/behat_theme_classic_behat_admin.php b/theme/classic/tests/behat/behat_theme_classic_behat_admin.php index 94b81f2bd00..e424776ed4c 100644 --- a/theme/classic/tests/behat/behat_theme_classic_behat_admin.php +++ b/theme/classic/tests/behat/behat_theme_classic_behat_admin.php @@ -56,17 +56,12 @@ class behat_theme_classic_behat_admin extends behat_admin { // We expect admin block to be visible, otherwise go to homepage. if (!$this->getSession()->getPage()->find('css', '.block_settings')) { - $this->getSession()->visit($this->locate_path('/')); - $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); + $this->execute('behat_forms::i_am_on_homepage'); } // Search by label. - $searchbox = $this->find_field(get_string('searchinsettings', 'admin')); - $searchbox->setValue($label); - $submitsearch = $this->find('css', 'form.adminsearchform input[type=submit]'); - $submitsearch->press(); - - $this->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS); + $this->execute('behat_forms::i_set_the_field_to', [get_string('searchinsettings', 'admin'), $label]); + $this->execute("behat_general::i_click_on_in_the", [get_string('search', 'admin'), 'button', '.block_settings', 'css_element']); // Admin settings does not use the same DOM structure than other moodle forms // but we also need to use lib/behat/form_field/* to deal with the different moodle form elements. @@ -82,11 +77,6 @@ class behat_theme_classic_behat_admin extends behat_admin { "[@id=//label[contains(normalize-space(.), $label)]/@for or " . "@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]"; $fieldnode = $this->find('xpath', $fieldxpath, $exception); - - $formfieldtypenode = $this->find('xpath', $fieldxpath . - "/ancestor::div[contains(concat(' ', @class, ' '), ' form-setting ')]" . - "/child::div[contains(concat(' ', @class, ' '), ' form-')]/child::*/parent::div"); - } catch (ElementNotFoundException $e) { // Multi element settings, interacting only the first one. @@ -96,25 +86,11 @@ class behat_theme_classic_behat_admin extends behat_admin { "/descendant::*[self::input | self::textarea | self::select]" . "[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]"; $fieldnode = $this->find('xpath', $fieldxpath); - - // It is the same one that contains the type. - $formfieldtypenode = $fieldnode; } - // Getting the class which contains the field type. - $classes = explode(' ', $formfieldtypenode->getAttribute('class')); - $type = false; - foreach ($classes as $class) { - if (substr($class, 0, 5) == 'form-') { - $type = substr($class, 5); - } - } + $this->execute('behat_forms::i_set_the_field_with_xpath_to', [$fieldxpath, $value]); - // Instantiating the appropiate field type. - $field = behat_field_manager::get_field_instance($type, $fieldnode, $this->getSession()); - $field->set_value($value); - - $this->find_button(get_string('savechanges'))->press(); + $this->execute("behat_general::i_click_on", [get_string('savechanges'), 'button']); } } }