diff --git a/mod/forum/amd/build/grades/expandconversation.min.js b/mod/forum/amd/build/grades/expandconversation.min.js
index 3a23728bb86..d4ea27e0f2a 100644
--- a/mod/forum/amd/build/grades/expandconversation.min.js
+++ b/mod/forum/amd/build/grades/expandconversation.min.js
@@ -1,2 +1,2 @@
-define ("mod_forum/grades/expandconversation",["exports","./grader/selectors","mod_forum/repository","core/notification","core/templates","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=i(b);c=h(c);e=h(e);f=i(f);g=i(g);function h(a){return a&&a.__esModule?a:{default:a}}function i(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function j(a,b){return m(a)||l(a,b)||k()}function k(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function l(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function m(a){if(Array.isArray(a))return a}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}var p=function(a){return a.closest(b.expandConversation)},q=function(){var a=o(regeneratorRuntime.mark(function a(b){var d,h,i,k,l,m,n,o,p,q,r;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=b.dataset.postid;h=b.dataset.discussionid;i=b.dataset.name;k="1"==b.dataset.experimentalDisplayMode;a.next=6;return Promise.all([c.default.getDiscussionPosts(parseInt(h)),f.create({title:i,large:!0,type:f.types.CANCEL})]);case 6:l=a.sent;m=j(l,2);n=m[0];o=m[1];p=new Map(n.posts.map(function(a){a.readonly=!0;a.hasreplies=!1;a.replies=[];return[a.id,a]}));q=[];n.posts.forEach(function(a){if(a.parentid){var b=p.get(a.parentid);if(b){a.parentauthorname=b.author.fullname;b.hasreplies=!0;b.replies.push(a)}else{q.push(a)}}else{q.push(a)}});o.getRoot().on(g.hidden,function(){o.destroy()});o.getRoot().on(g.bodyRendered,function(){var a=o.getRoot()[0].querySelector("#p".concat(d));if(a){a.scrollIntoView({behavior:"smooth"})}});o.show();r=e.default.render("mod_forum/grades/grader/discussion/post_modal",{posts:q,experimentaldisplaymode:k});o.setBody(r);case 18:case"end":return a.stop();}}},a)}));return function(){return a.apply(this,arguments)}}();a.registerEventListeners=function registerEventListeners(a){a.addEventListener("click",function(a){var b=p(a.target);if(b){a.preventDefault();try{q(b)}catch(a){(0,d.exception)(a)}}})}});
+define ("mod_forum/grades/expandconversation",["exports","./grader/selectors","mod_forum/repository","core/notification","core/templates","core/modal_factory","core/modal_events"],function(a,b,c,d,e,f,g){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.registerEventListeners=void 0;b=i(b);c=h(c);e=h(e);f=i(f);g=i(g);function h(a){return a&&a.__esModule?a:{default:a}}function i(a){if(a&&a.__esModule){return a}else{var b={};if(null!=a){for(var c in a){if(Object.prototype.hasOwnProperty.call(a,c)){var d=Object.defineProperty&&Object.getOwnPropertyDescriptor?Object.getOwnPropertyDescriptor(a,c):{};if(d.get||d.set){Object.defineProperty(b,c,d)}else{b[c]=a[c]}}}}b.default=a;return b}}function j(a,b){return m(a)||l(a,b)||k()}function k(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}function l(a,b){var c=[],d=!0,e=!1,f=void 0;try{for(var g=a[Symbol.iterator](),h;!(d=(h=g.next()).done);d=!0){c.push(h.value);if(b&&c.length===b)break}}catch(a){e=!0;f=a}finally{try{if(!d&&null!=g["return"])g["return"]()}finally{if(e)throw f}}return c}function m(a){if(Array.isArray(a))return a}function n(a,b,c,d,e,f,g){try{var h=a[f](g),i=h.value}catch(a){c(a);return}if(h.done){b(i)}else{Promise.resolve(i).then(d,e)}}function o(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){n(h,d,e,f,g,"next",a)}function g(a){n(h,d,e,f,g,"throw",a)}f(void 0)})}}var p=function(a){return a.closest(b.expandConversation)},q=function(){var a=o(regeneratorRuntime.mark(function a(b){var d,h,i,k,l,m,n,o,p,q,r,s,t,u,v=arguments;return regeneratorRuntime.wrap(function(a){while(1){switch(a.prev=a.next){case 0:d=1.\n\n/**\n * This module handles the creation of a Modal that shows the user's post in context of the entire discussion.\n *\n * @module mod_forum/grades/expandconversation\n * @package mod_forum\n * @copyright 2019 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as ForumSelectors from './grader/selectors';\nimport Repository from 'mod_forum/repository';\nimport {exception as showException} from \"core/notification\";\nimport Templates from 'core/templates';\nimport * as Modal from 'core/modal_factory';\nimport * as ModalEvents from 'core/modal_events';\n\n/**\n * Find the Node containing the gradable details from the provided node by searching up the tree.\n *\n * @param {HTMLElement} node\n * @returns {HTMLElement}\n */\nconst findGradableNode = node => node.closest(ForumSelectors.expandConversation);\n\n/**\n * Show the post in context in a modal.\n *\n * @param {HTMLElement} rootNode The button that has been clicked\n */\nconst showPostInContext = async(rootNode) => {\n const postId = rootNode.dataset.postid;\n const discussionId = rootNode.dataset.discussionid;\n const discussionName = rootNode.dataset.name;\n const experimentalDisplayMode = rootNode.dataset.experimentalDisplayMode == \"1\";\n\n const [\n allPosts,\n modal,\n ] = await Promise.all([\n Repository.getDiscussionPosts(parseInt(discussionId)),\n Modal.create({\n title: discussionName,\n large: true,\n type: Modal.types.CANCEL\n }),\n ]);\n\n const postsById = new Map(allPosts.posts.map(post => {\n post.readonly = true;\n post.hasreplies = false;\n post.replies = [];\n return [post.id, post];\n }));\n\n let posts = [];\n allPosts.posts.forEach(post => {\n if (post.parentid) {\n const parent = postsById.get(post.parentid);\n if (parent) {\n post.parentauthorname = parent.author.fullname;\n parent.hasreplies = true;\n parent.replies.push(post);\n } else {\n posts.push(post);\n }\n } else {\n posts.push(post);\n }\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function() {\n // Destroy when hidden.\n modal.destroy();\n });\n\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n const relevantPost = modal.getRoot()[0].querySelector(`#p${postId}`);\n if (relevantPost) {\n relevantPost.scrollIntoView({behavior: \"smooth\"});\n }\n });\n\n modal.show();\n\n // Note: We do not use await here because it messes with the Modal transitions.\n const templatePromise = Templates.render('mod_forum/grades/grader/discussion/post_modal', {\n posts,\n experimentaldisplaymode: experimentalDisplayMode\n });\n modal.setBody(templatePromise);\n};\n\n/**\n * Register event listeners for the expand conversations button.\n *\n * @param {HTMLElement} rootNode The root to listen to.\n */\nexport const registerEventListeners = (rootNode) => {\n rootNode.addEventListener('click', (e) => {\n const rootNode = findGradableNode(e.target);\n\n if (rootNode) {\n e.preventDefault();\n\n try {\n showPostInContext(rootNode);\n } catch (err) {\n showException(err);\n }\n }\n });\n};\n"],"file":"expandconversation.min.js"}
\ No newline at end of file
+{"version":3,"sources":["../../src/grades/expandconversation.js"],"names":["findGradableNode","node","closest","ForumSelectors","expandConversation","showPostInContext","rootNode","focusOnClose","postId","dataset","postid","discussionId","discussionid","discussionName","name","experimentalDisplayMode","Promise","all","Repository","getDiscussionPosts","parseInt","Modal","create","title","large","type","types","CANCEL","allPosts","modal","postsById","Map","posts","map","post","readonly","hasreplies","replies","id","forEach","parentid","parent","get","parentauthorname","author","fullname","push","getRoot","on","ModalEvents","hidden","destroy","focus","e","bodyRendered","relevantPost","querySelector","scrollIntoView","behavior","show","templatePromise","Templates","render","experimentaldisplaymode","setBody","registerEventListeners","addEventListener","target","preventDefault","err"],"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 * This module handles the creation of a Modal that shows the user's post in context of the entire discussion.\n *\n * @module mod_forum/grades/expandconversation\n * @package mod_forum\n * @copyright 2019 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport * as ForumSelectors from './grader/selectors';\nimport Repository from 'mod_forum/repository';\nimport {exception as showException} from \"core/notification\";\nimport Templates from 'core/templates';\nimport * as Modal from 'core/modal_factory';\nimport * as ModalEvents from 'core/modal_events';\n\n/**\n * Find the Node containing the gradable details from the provided node by searching up the tree.\n *\n * @param {HTMLElement} node\n * @returns {HTMLElement}\n */\nconst findGradableNode = node => node.closest(ForumSelectors.expandConversation);\n\n/**\n * Show the post in context in a modal.\n *\n * @param {HTMLElement} rootNode The button that has been clicked\n */\nconst showPostInContext = async(rootNode, {\n focusOnClose = null,\n} = {}) => {\n const postId = rootNode.dataset.postid;\n const discussionId = rootNode.dataset.discussionid;\n const discussionName = rootNode.dataset.name;\n const experimentalDisplayMode = rootNode.dataset.experimentalDisplayMode == \"1\";\n\n const [\n allPosts,\n modal,\n ] = await Promise.all([\n Repository.getDiscussionPosts(parseInt(discussionId)),\n Modal.create({\n title: discussionName,\n large: true,\n type: Modal.types.CANCEL\n }),\n ]);\n\n const postsById = new Map(allPosts.posts.map(post => {\n post.readonly = true;\n post.hasreplies = false;\n post.replies = [];\n return [post.id, post];\n }));\n\n let posts = [];\n allPosts.posts.forEach(post => {\n if (post.parentid) {\n const parent = postsById.get(post.parentid);\n if (parent) {\n post.parentauthorname = parent.author.fullname;\n parent.hasreplies = true;\n parent.replies.push(post);\n } else {\n posts.push(post);\n }\n } else {\n posts.push(post);\n }\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function() {\n // Destroy when hidden.\n modal.destroy();\n try {\n focusOnClose.focus();\n } catch (e) {\n // eslint-disable-line\n }\n });\n\n modal.getRoot().on(ModalEvents.bodyRendered, () => {\n const relevantPost = modal.getRoot()[0].querySelector(`#p${postId}`);\n if (relevantPost) {\n relevantPost.scrollIntoView({behavior: \"smooth\"});\n }\n });\n\n modal.show();\n\n // Note: We do not use await here because it messes with the Modal transitions.\n const templatePromise = Templates.render('mod_forum/grades/grader/discussion/post_modal', {\n posts,\n experimentaldisplaymode: experimentalDisplayMode\n });\n modal.setBody(templatePromise);\n};\n\n/**\n * Register event listeners for the expand conversations button.\n *\n * @param {HTMLElement} rootNode The root to listen to.\n */\nexport const registerEventListeners = (rootNode) => {\n rootNode.addEventListener('click', (e) => {\n const rootNode = findGradableNode(e.target);\n\n if (rootNode) {\n e.preventDefault();\n\n try {\n showPostInContext(rootNode, {\n focusOnClose: e.target,\n });\n } catch (err) {\n showException(err);\n }\n }\n });\n};\n"],"file":"expandconversation.min.js"}
\ No newline at end of file
diff --git a/mod/forum/amd/src/grades/expandconversation.js b/mod/forum/amd/src/grades/expandconversation.js
index cb9757e3334..c2b75f399cf 100644
--- a/mod/forum/amd/src/grades/expandconversation.js
+++ b/mod/forum/amd/src/grades/expandconversation.js
@@ -41,7 +41,9 @@ const findGradableNode = node => node.closest(ForumSelectors.expandConversation)
*
* @param {HTMLElement} rootNode The button that has been clicked
*/
-const showPostInContext = async(rootNode) => {
+const showPostInContext = async(rootNode, {
+ focusOnClose = null,
+} = {}) => {
const postId = rootNode.dataset.postid;
const discussionId = rootNode.dataset.discussionid;
const discussionName = rootNode.dataset.name;
@@ -86,6 +88,11 @@ const showPostInContext = async(rootNode) => {
modal.getRoot().on(ModalEvents.hidden, function() {
// Destroy when hidden.
modal.destroy();
+ try {
+ focusOnClose.focus();
+ } catch (e) {
+ // eslint-disable-line
+ }
});
modal.getRoot().on(ModalEvents.bodyRendered, () => {
@@ -118,7 +125,9 @@ export const registerEventListeners = (rootNode) => {
e.preventDefault();
try {
- showPostInContext(rootNode);
+ showPostInContext(rootNode, {
+ focusOnClose: e.target,
+ });
} catch (err) {
showException(err);
}