From 7902e4dc556665a39c2877b53655faa4822dbe72 Mon Sep 17 00:00:00 2001 From: Ryan Wyllie Date: Wed, 28 Aug 2019 15:27:10 +0800 Subject: [PATCH] MDL-64821 mod_forum: add show/hide reply toggle for modern view --- mod/forum/amd/build/discussion_modern.min.js | 2 +- .../amd/build/discussion_modern.min.js.map | 2 +- mod/forum/amd/build/inpage_reply.min.js | 2 +- mod/forum/amd/build/inpage_reply.min.js.map | 2 +- mod/forum/amd/build/selectors.min.js | 2 +- mod/forum/amd/build/selectors.min.js.map | 2 +- mod/forum/amd/src/discussion_modern.js | 302 +++++++++++++++--- mod/forum/amd/src/inpage_reply.js | 8 +- mod/forum/amd/src/selectors.js | 9 +- mod/forum/lang/en/forum.php | 2 + ...orum_discussion_modern_post_reply.mustache | 16 + 11 files changed, 295 insertions(+), 54 deletions(-) diff --git a/mod/forum/amd/build/discussion_modern.min.js b/mod/forum/amd/build/discussion_modern.min.js index 294fa113641..5750fc3c0be 100644 --- a/mod/forum/amd/build/discussion_modern.min.js +++ b/mod/forum/amd/build/discussion_modern.min.js @@ -1,2 +1,2 @@ -define ("mod_forum/discussion_modern",["exports","jquery","core/auto_rows","core/custom_interaction_events","core/notification","core/templates","mod_forum/discussion","mod_forum/inpage_reply","mod_forum/lock_toggle","mod_forum/favourite_toggle","mod_forum/pin_toggle","mod_forum/selectors"],function(a,b,c,d,f,g,h,i,j,k,l,m){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;b=n(b);c=n(c);d=n(d);f=n(f);g=n(g);h=n(h);i=n(i);j=n(j);k=n(k);l=n(l);m=n(m);function n(a){return a&&a.__esModule?a:{default:a}}function o(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 p(a){return function(){var b=this,c=arguments;return new Promise(function(d,e){var h=a.apply(b,c);function f(a){o(h,d,e,f,g,"next",a)}function g(a){o(h,d,e,f,g,"throw",a)}f(void 0)})}}function q(a){for(var b=1;b.\n\n/**\n * Module for viewing a discussion in modern view.\n *\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport $ from 'jquery';\nimport AutoRows from 'core/auto_rows';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Discussion from 'mod_forum/discussion';\nimport InPageReply from 'mod_forum/inpage_reply';\nimport LockToggle from 'mod_forum/lock_toggle';\nimport FavouriteToggle from 'mod_forum/favourite_toggle';\nimport Pin from 'mod_forum/pin_toggle';\nimport Selectors from 'mod_forum/selectors';\n\nconst ANIMATION_DURATION = 150;\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getPostContainer = (element) => {\n return element.closest(Selectors.post.post);\n};\n\n/**\n * Get the post content container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getPostContentContainer = (postContainer) => {\n return postContainer.children().not(Selectors.post.repliesContainer).find(Selectors.post.forumCoreContent);\n};\n\n/**\n * Get the in page reply container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyContainer = (postContainer) => {\n return postContainer.children().filter(Selectors.post.inpageReplyContainer);\n};\n\n/**\n * Show the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @param {Function} afterAnimationCallback Callback after animation completes\n */\nconst showInPageReplyForm = (inPageReplyContainer, afterAnimationCallback) => {\n const form = inPageReplyContainer.find(Selectors.post.inpageReplyContent);\n\n form.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: afterAnimationCallback\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n};\n\n/**\n * Hide the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @param {Function} afterAnimationCallback Callback after animation completes\n */\nconst hideInPageReplyForm = (inPageReplyContainer, afterAnimationCallback) => {\n const form = inPageReplyContainer.find(Selectors.post.inpageReplyContent);\n\n form.slideUp({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: afterAnimationCallback\n }).fadeOut(200);\n};\n\n/**\n * Check if the in page reply container contains the in page reply form.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @return {Bool}\n */\nconst hasInPageReplyForm = (inPageReplyContainer) => {\n return inPageReplyContainer.find(Selectors.post.inpageReplyContent).length > 0;\n};\n\n/**\n * Render the template to generate the in page reply form HTML.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template\n * @param {Object} button jQuery element for the reply button that was clicked\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery promise\n */\nconst renderInPageReplyTemplate = (additionalTemplateContext, button, postContainer) => {\n const postContentContainer = getPostContentContainer(postContainer);\n const currentSubject = postContentContainer.find(Selectors.post.forumSubject).text();\n const currentAuthorName = postContentContainer.find(Selectors.post.authorName).text();\n const context = {\n postid: postContainer.data('post-id'),\n \"reply_url\": button.attr('data-href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject,\n parentauthorname: currentAuthorName,\n canreplyprivately: button.data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE,\n ...additionalTemplateContext\n };\n\n return Templates.render('mod_forum/inpage_reply_modern', context);\n};\n\n/**\n * Create all of the event listeners for the discussion.\n *\n * @param {Object} root jQuery element for the discussion container\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template\n */\nconst registerEventListeners = (root, additionalTemplateContext) => {\n CustomEvents.define(root, [CustomEvents.events.activate]);\n // Auto expanding text area for in page reply.\n AutoRows.init(root);\n\n // Reply button is clicked.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, async (e, data) => {\n data.originalEvent.preventDefault();\n\n const button = $(e.currentTarget);\n const postContainer = getPostContainer(button);\n const inPageReplyContainer = getInPageReplyContainer(postContainer);\n\n if (!hasInPageReplyForm(inPageReplyContainer)) {\n try {\n const html = await renderInPageReplyTemplate(additionalTemplateContext, button, postContainer);\n Templates.appendNodeContents(inPageReplyContainer, html, '');\n } catch (e) {\n Notification.exception(e);\n }\n }\n\n button.fadeOut(ANIMATION_DURATION, () => {\n showInPageReplyForm(inPageReplyContainer, () => {\n inPageReplyContainer.find(Selectors.post.inpageReplyContent).find('textarea').focus();\n });\n });\n });\n\n // Cancel in page reply button.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCancelButton, (e, data) => {\n data.originalEvent.preventDefault();\n\n const button = $(e.currentTarget);\n const postContainer = getPostContainer(button);\n const postContentContainer = getPostContentContainer(postContainer);\n const inPageReplyContainer = getInPageReplyContainer(postContainer);\n const inPageReplyCreateButton = postContentContainer.find(Selectors.post.inpageReplyCreateButton);\n hideInPageReplyForm(inPageReplyContainer, () => {\n inPageReplyCreateButton.fadeIn(ANIMATION_DURATION);\n });\n });\n};\n\n/**\n * Initialise the javascript for the discussion in modern display mode.\n *\n * @param {Object} root jQuery element for the discussion container\n * @param {Object} context Additional render context for the in page reply template\n */\nexport const init = (root, context) => {\n // Add discussion event listeners.\n registerEventListeners(root, context);\n // Add default discussion javascript (keyboard nav etc).\n Discussion.init(root);\n // Add in page reply javascript.\n InPageReply.init(root);\n\n // Initialise the settings menu javascript.\n const discussionToolsContainer = root.find('[data-container=\"discussion-tools\"]');\n LockToggle.init(discussionToolsContainer);\n FavouriteToggle.init(discussionToolsContainer);\n Pin.init(discussionToolsContainer);\n};\n"],"file":"discussion_modern.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/discussion_modern.js"],"names":["getPostContainer","element","closest","Selectors","post","getPostContainerById","id","find","getParentPostContainers","parents","getPostContentContainer","postContainer","children","not","repliesContainer","forumCoreContent","getInPageReplyContainer","filter","inpageReplyContainer","getInPageReplyForm","inpageReplyContent","getInPageReplyCreateButton","inpageReplyCreateButton","getRepliesVisibilityToggleContainer","repliesVisibilityToggleContainer","getRepliesContainer","hasReplies","length","getShowRepliesButton","replyVisibilityToggleContainer","showReplies","getHideRepliesButton","hideReplies","repliesVisible","is","postIdToSee","showButton","hideButton","addClass","removeClass","slideDown","duration","queue","complete","postContainerToSee","scrollIntoView","css","fadeIn","slideUp","fadeOut","showInPageReplyForm","buildShowInPageReplyFormFunction","additionalTemplateContext","inPageReplyContainer","inPageReplyCreateButton","hasInPageReplyForm","renderInPageReplyTemplate","html","Templates","appendNodeContents","Notification","exception","inPageReplyForm","focus","hideInPageReplyForm","button","postContentContainer","currentSubject","forumSubject","text","currentAuthorName","authorName","context","postid","data","attr","sesskey","M","cfg","parentsubject","parentauthorname","canreplyprivately","postformat","InPageReply","CONTENT_FORMATS","MOODLE","render","incrementTotalReplyCount","replyCount","each","index","currentCount","parseInt","innerText","registerEventListeners","root","CustomEvents","define","events","activate","AutoRows","init","on","e","originalEvent","preventDefault","currentTarget","inpageReplyCancelButton","target","EVENTS","POST_CREATED","inpageSubmitBtn","newPostId","postContainers","container","Discussion","discussionToolsContainer","discussion","tools","LockToggle","FavouriteToggle","Pin"],"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 * Module for viewing a discussion in modern view.\n *\n * @copyright 2019 Ryan Wyllie \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\nimport $ from 'jquery';\nimport AutoRows from 'core/auto_rows';\nimport CustomEvents from 'core/custom_interaction_events';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport Discussion from 'mod_forum/discussion';\nimport InPageReply from 'mod_forum/inpage_reply';\nimport LockToggle from 'mod_forum/lock_toggle';\nimport FavouriteToggle from 'mod_forum/favourite_toggle';\nimport Pin from 'mod_forum/pin_toggle';\nimport Selectors from 'mod_forum/selectors';\n\nconst ANIMATION_DURATION = 150;\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getPostContainer = (element) => {\n return element.closest(Selectors.post.post);\n};\n\n/**\n * Get the closest post container element from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @param {Number} id Id of the post to find.\n * @return {Object} jQuery element\n */\nconst getPostContainerById = (element, id) => {\n return element.find(`${Selectors.post.post}[data-post-id=${id}]`);\n};\n\n/**\n * Get the parent post container elements from the given element.\n *\n * @param {Object} element jQuery element to search from\n * @return {Object} jQuery element\n */\nconst getParentPostContainers = (element) => {\n return element.parents(Selectors.post.post);\n};\n\n/**\n * Get the post content container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getPostContentContainer = (postContainer) => {\n return postContainer.children().not(Selectors.post.repliesContainer).find(Selectors.post.forumCoreContent);\n};\n\n/**\n * Get the in page reply container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyContainer = (postContainer) => {\n return postContainer.children().filter(Selectors.post.inpageReplyContainer);\n};\n\n/**\n * Get the in page reply form element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyForm = (postContainer) => {\n return getInPageReplyContainer(postContainer).find(Selectors.post.inpageReplyContent);\n};\n\n/**\n * Get the in page reply create (reply) button element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getInPageReplyCreateButton = (postContainer) => {\n return getPostContentContainer(postContainer).find(Selectors.post.inpageReplyCreateButton);\n};\n\n/**\n * Get the replies visibility toggle container (show/hide replies button container) element\n * from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesVisibilityToggleContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesVisibilityToggleContainer);\n};\n\n/**\n * Get the replies container element from the post container element.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery element\n */\nconst getRepliesContainer = (postContainer) => {\n return postContainer.children(Selectors.post.repliesContainer);\n};\n\n/**\n * Check if the post has any replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst hasReplies = (postContainer) => {\n return getRepliesContainer(postContainer).children().length > 0;\n};\n\n/**\n * Get the show replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getShowRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.showReplies);\n};\n\n/**\n * Get the hide replies button element from the replies visibility toggle container element.\n *\n * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container\n * @return {Object} jQuery element\n */\nconst getHideRepliesButton = (replyVisibilityToggleContainer) => {\n return replyVisibilityToggleContainer.find(Selectors.post.hideReplies);\n};\n\n/**\n * Check if the replies are visible.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @return {Bool}\n */\nconst repliesVisible = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n return repliesContainer.is(':visible');\n};\n\n/**\n * Show the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst showReplies = (postContainer, postIdToSee = null) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.addClass('hidden');\n hideButton.removeClass('hidden');\n\n repliesContainer.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n if (postIdToSee) {\n const postContainerToSee = getPostContainerById(repliesContainer, postIdToSee);\n if (postContainerToSee.length) {\n postContainerToSee[0].scrollIntoView();\n }\n }\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n};\n\n/**\n * Hide the post replies.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst hideReplies = (postContainer) => {\n const repliesContainer = getRepliesContainer(postContainer);\n const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const showButton = getShowRepliesButton(replyVisibilityToggleContainer);\n const hideButton = getHideRepliesButton(replyVisibilityToggleContainer);\n\n showButton.removeClass('hidden');\n hideButton.addClass('hidden');\n\n repliesContainer.slideUp({\n duration: ANIMATION_DURATION,\n queue: false\n }).fadeOut(ANIMATION_DURATION);\n};\n\n/** Variable to hold the showInPageReplyForm function after it's built. */\nlet showInPageReplyForm = null;\n\n/**\n * Build the showInPageReplyForm function with the given additional template context.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template.\n * @return {Function}\n */\nconst buildShowInPageReplyFormFunction = (additionalTemplateContext) => {\n /**\n * Show the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\n return async (postContainer) => {\n\n const inPageReplyContainer = getInPageReplyContainer(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n\n if (!hasInPageReplyForm(inPageReplyContainer)) {\n try {\n const html = await renderInPageReplyTemplate(additionalTemplateContext, inPageReplyCreateButton, postContainer);\n Templates.appendNodeContents(inPageReplyContainer, html, '');\n } catch (e) {\n Notification.exception(e);\n }\n }\n\n inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n inPageReplyForm.slideDown({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyForm.find('textarea').focus();\n }\n }).css('display', 'none').fadeIn(ANIMATION_DURATION);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeIn(ANIMATION_DURATION);\n hideReplies(postContainer);\n }\n });\n };\n};\n\n/**\n * Hide the in page reply form in the given in page reply container. The form\n * display will be animated.\n *\n * @param {Object} postContainer jQuery element for the post container\n * @param {Number|null} postIdToSee Id of the post to scroll into view (if any)\n */\nconst hideInPageReplyForm = (postContainer, postIdToSee = null) => {\n const inPageReplyForm = getInPageReplyForm(postContainer);\n const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer);\n const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer);\n\n if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) {\n repliesVisibilityToggleContainer.fadeOut(ANIMATION_DURATION);\n if (!repliesVisible(postContainer)) {\n showReplies(postContainer, postIdToSee);\n }\n }\n\n inPageReplyForm.slideUp({\n duration: ANIMATION_DURATION,\n queue: false,\n complete: () => {\n inPageReplyCreateButton.fadeIn(ANIMATION_DURATION);\n }\n }).fadeOut(200);\n};\n\n/**\n * Check if the in page reply container contains the in page reply form.\n *\n * @param {Object} inPageReplyContainer jQuery element for the in page reply container\n * @return {Bool}\n */\nconst hasInPageReplyForm = (inPageReplyContainer) => {\n return inPageReplyContainer.find(Selectors.post.inpageReplyContent).length > 0;\n};\n\n/**\n * Render the template to generate the in page reply form HTML.\n *\n * @param {Object} additionalTemplateContext Additional render context for the in page reply template\n * @param {Object} button jQuery element for the reply button that was clicked\n * @param {Object} postContainer jQuery element for the post container\n * @return {Object} jQuery promise\n */\nconst renderInPageReplyTemplate = (additionalTemplateContext, button, postContainer) => {\n const postContentContainer = getPostContentContainer(postContainer);\n const currentSubject = postContentContainer.find(Selectors.post.forumSubject).text();\n const currentAuthorName = postContentContainer.find(Selectors.post.authorName).text();\n const context = {\n postid: postContainer.data('post-id'),\n \"reply_url\": button.attr('data-href'),\n sesskey: M.cfg.sesskey,\n parentsubject: currentSubject,\n parentauthorname: currentAuthorName,\n canreplyprivately: button.data('can-reply-privately'),\n postformat: InPageReply.CONTENT_FORMATS.MOODLE,\n ...additionalTemplateContext\n };\n\n return Templates.render('mod_forum/inpage_reply_modern', context);\n};\n\n/**\n * Increment the total reply count in the show/hide replies buttons for the post.\n *\n * @param {Object} postContainer jQuery element for the post container\n */\nconst incrementTotalReplyCount = (postContainer) => {\n getRepliesVisibilityToggleContainer(postContainer).find(Selectors.post.replyCount).each((index, element) => {\n const currentCount = parseInt(element.innerText, 10);\n element.innerText = currentCount + 1;\n });\n};\n\n/**\n * Create all of the event listeners for the discussion.\n *\n * @param {Object} root jQuery element for the discussion container\n */\nconst registerEventListeners = (root) => {\n CustomEvents.define(root, [CustomEvents.events.activate]);\n // Auto expanding text area for in page reply.\n AutoRows.init(root);\n\n // Reply button is clicked.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n showInPageReplyForm(postContainer);\n });\n\n // Cancel in page reply button.\n root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCancelButton, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.currentTarget));\n hideInPageReplyForm(postContainer);\n });\n\n // Show replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.showReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n showReplies(postContainer);\n });\n\n // Hide replies button clicked.\n root.on(CustomEvents.events.activate, Selectors.post.hideReplies, (e, data) => {\n data.originalEvent.preventDefault();\n const postContainer = getPostContainer($(e.target));\n hideReplies(postContainer);\n });\n\n // Post created with in page reply.\n root.on(InPageReply.EVENTS.POST_CREATED, Selectors.post.inpageSubmitBtn, (e, newPostId) => {\n const currentTarget = $(e.currentTarget);\n const postContainer = getPostContainer(currentTarget);\n const postContainers = getParentPostContainers(currentTarget);\n hideInPageReplyForm(postContainer, newPostId);\n\n postContainers.each((index, container) => {\n incrementTotalReplyCount($(container));\n });\n });\n};\n\n/**\n * Initialise the javascript for the discussion in modern display mode.\n *\n * @param {Object} root jQuery element for the discussion container\n * @param {Object} context Additional render context for the in page reply template\n */\nexport const init = (root, context) => {\n // Build the showInPageReplyForm function with the additional render context.\n showInPageReplyForm = buildShowInPageReplyFormFunction(context);\n // Add discussion event listeners.\n registerEventListeners(root);\n // Initialise default discussion javascript (keyboard nav etc).\n Discussion.init(root);\n // Add in page reply javascript.\n InPageReply.init(root);\n\n // Initialise the settings menu javascript.\n const discussionToolsContainer = root.find(Selectors.discussion.tools);\n LockToggle.init(discussionToolsContainer);\n FavouriteToggle.init(discussionToolsContainer);\n Pin.init(discussionToolsContainer);\n};\n"],"file":"discussion_modern.min.js"} \ No newline at end of file diff --git a/mod/forum/amd/build/inpage_reply.min.js b/mod/forum/amd/build/inpage_reply.min.js index 25220460da6..49ab60e7874 100644 --- a/mod/forum/amd/build/inpage_reply.min.js +++ b/mod/forum/amd/build/inpage_reply.min.js @@ -1,2 +1,2 @@ -define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,f){var g={MODERN:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},h={MOODLE:0},i=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},j=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},k=function(k){k.on("click",f.post.inpageSubmitBtn,function(l){l.preventDefault();var e=a(l.currentTarget),m=e.parent().find(f.post.inpageReplyButton),n=e.parents(f.post.inpageReplyForm).get(0),o=n.elements.post.value.trim(),p=h.MOODLE,q=n.elements.reply.value,r=n.elements.subject.value,s=e.closest(f.post.post),t=n.elements.privatereply!=void 0?n.elements.privatereply.checked:!1,u=k.find(f.post.modeSelect),v=u.length?parseInt(u.get(0).value):null,w;if(o.length){i(e);m.prop("disabled",!0);d.addDiscussionPost(q,r,o,p,t,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+="

"+b.message+"

"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){n.reset();var c=a.post;w=c.id;switch(v){case g.MODERN:var d=c.capabilities;c.showactionmenu=d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_modern_post_reply",c);case g.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case g.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=s.find(f.post.repliesContainer).first();if(v==g.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){j(e);m.prop("disabled",!1);return s.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+w}).catch(function(a){j(e);m.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){k(a)},CONTENT_FORMATS:h}}); +define ("mod_forum/inpage_reply",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,f){var g={MODERN:4,THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},h={POST_CREATED:"mod_forum-post-created"},i={MOODLE:0},j=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer),d=a.outerWidth();a.css("width",d);b.addClass("hidden");c.removeClass("hidden")},k=function(a){var b=a.find(f.post.inpageSubmitBtnText),c=a.find(f.post.loadingIconContainer);a.css("width","");b.removeClass("hidden");c.addClass("hidden")},l=function(l){l.on("click",f.post.inpageSubmitBtn,function(m){m.preventDefault();var e=a(m.currentTarget),n=e.parent().find(f.post.inpageReplyButton),o=e.parents(f.post.inpageReplyForm).get(0),p=o.elements.post.value.trim(),q=i.MOODLE,r=o.elements.reply.value,s=o.elements.subject.value,t=e.closest(f.post.post),u=o.elements.privatereply!=void 0?o.elements.privatereply.checked:!1,v=l.find(f.post.modeSelect),w=v.length?parseInt(v.get(0).value):null,x;if(p.length){j(e);n.prop("disabled",!0);d.addDiscussionPost(r,s,p,q,u,!0).then(function(a){var b=a.messages.reduce(function(a,b){if("success"==b.type){a+="

"+b.message+"

"}return a},"");c.addNotification({message:b,type:"success"});return a}).then(function(a){o.reset();var c=a.post;x=c.id;switch(w){case g.MODERN:var d=c.capabilities;c.showactionmenu=d.controlreadstatus||d.edit||d.split||d.delete||d.export||c.urls.viewparent;return b.render("mod_forum/forum_discussion_modern_post_reply",c);case g.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case g.NESTED:return b.render("mod_forum/forum_discussion_nested_post",c);default:return b.render("mod_forum/forum_discussion_post",c);}}).then(function(a,c){var d=t.find(f.post.repliesContainer).first();if(w==g.FLAT_NEWEST_FIRST){return b.prependNodeContents(d,a,c)}else{return b.appendNodeContents(d,a,c)}}).then(function(){e.trigger(h.POST_CREATED,x);k(e);n.prop("disabled",!1);return t.find(f.post.inpageReplyContent).hide()}).then(function(){location.href="#p"+x}).catch(function(a){k(e);n.prop("disabled",!1);return c.exception(a)})}})};return{init:function init(a){l(a)},CONTENT_FORMATS:i,EVENTS:h}}); //# sourceMappingURL=inpage_reply.min.js.map diff --git a/mod/forum/amd/build/inpage_reply.min.js.map b/mod/forum/amd/build/inpage_reply.min.js.map index a5ea0044d45..097c4c3a2e8 100644 --- a/mod/forum/amd/build/inpage_reply.min.js.map +++ b/mod/forum/amd/build/inpage_reply.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/inpage_reply.js"],"names":["define","$","Templates","Notification","Repository","Selectors","DISPLAYCONSTANTS","MODERN","THREADED","NESTED","FLAT_OLDEST_FIRST","FLAT_NEWEST_FIRST","CONTENT_FORMATS","MOODLE","showSubmitButtonLoadingIcon","button","textContainer","find","post","inpageSubmitBtnText","loadingIconContainer","width","outerWidth","css","addClass","removeClass","hideSubmitButtonLoadingIcon","registerEventListeners","root","on","inpageSubmitBtn","e","preventDefault","submitButton","currentTarget","allButtons","parent","inpageReplyButton","form","parents","inpageReplyForm","get","message","elements","value","trim","messageformat","postid","reply","subject","currentRoot","closest","isprivatereply","privatereply","checked","modeSelector","modeSelect","mode","length","parseInt","newid","prop","addDiscussionPost","then","context","messages","reduce","carry","type","addNotification","reset","id","capabilities","showactionmenu","controlreadstatus","edit","split","delete","export","urls","viewparent","render","html","js","repliesnode","repliesContainer","first","prependNodeContents","appendNodeContents","inpageReplyContent","hide","location","href","catch","error","exception","init"],"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 in page replying to forum posts.\n *\n * @module mod_forum/inpage_reply\n * @package mod_forum\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'mod_forum/repository',\n 'mod_forum/selectors',\n ], function(\n $,\n Templates,\n Notification,\n Repository,\n Selectors\n ) {\n\n var DISPLAYCONSTANTS = {\n MODERN: 4,\n THREADED: 2,\n NESTED: 3,\n FLAT_OLDEST_FIRST: 1,\n FLAT_NEWEST_FIRST: -1\n };\n\n /**\n * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.\n * @type {Object}\n */\n var CONTENT_FORMATS = {\n MOODLE: 0\n };\n /**\n * Show the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var showSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n var width = button.outerWidth();\n // Fix the width so that the button size doesn't change when we show the loading icon.\n button.css('width', width);\n textContainer.addClass('hidden');\n loadingIconContainer.removeClass('hidden');\n };\n\n /**\n * Hide the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var hideSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n // Reset the width back to it's default.\n button.css('width', '');\n textContainer.removeClass('hidden');\n loadingIconContainer.addClass('hidden');\n };\n\n /**\n * Register the event listeners for the submit button of the in page reply.\n *\n * @param {Object} root The discussion container element.\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageSubmitBtn, function(e) {\n e.preventDefault();\n var submitButton = $(e.currentTarget);\n var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);\n var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);\n var message = form.elements.post.value.trim();\n // For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).\n // In the future, other formats should be supported, letting users to use their preferred editor and format.\n var messageformat = CONTENT_FORMATS.MOODLE;\n // The message post will be converted from messageformat to FORMAT_HTML.\n var topreferredformat = true;\n var postid = form.elements.reply.value;\n var subject = form.elements.subject.value;\n var currentRoot = submitButton.closest(Selectors.post.post);\n var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;\n var modeSelector = root.find(Selectors.post.modeSelect);\n var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;\n var newid;\n\n if (message.length) {\n showSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', true);\n\n Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)\n .then(function(context) {\n var message = context.messages.reduce(function(carry, message) {\n if (message.type == 'success') {\n carry += '

' + message.message + '

';\n }\n return carry;\n }, '');\n Notification.addNotification({\n message: message,\n type: \"success\"\n });\n\n return context;\n })\n .then(function(context) {\n form.reset();\n var post = context.post;\n newid = post.id;\n\n switch (mode) {\n case DISPLAYCONSTANTS.MODERN:\n var capabilities = post.capabilities;\n post.showactionmenu = capabilities.controlreadstatus ||\n capabilities.edit ||\n capabilities.split ||\n capabilities.delete ||\n capabilities.export ||\n post.urls.viewparent;\n return Templates.render('mod_forum/forum_discussion_modern_post_reply', post);\n case DISPLAYCONSTANTS.THREADED:\n return Templates.render('mod_forum/forum_discussion_threaded_post', post);\n case DISPLAYCONSTANTS.NESTED:\n return Templates.render('mod_forum/forum_discussion_nested_post', post);\n default:\n return Templates.render('mod_forum/forum_discussion_post', post);\n }\n })\n .then(function(html, js) {\n var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();\n\n if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {\n return Templates.prependNodeContents(repliesnode, html, js);\n } else {\n return Templates.appendNodeContents(repliesnode, html, js);\n }\n })\n .then(function() {\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return currentRoot.find(Selectors.post.inpageReplyContent).hide();\n })\n .then(function() {\n location.href = \"#p\" + newid;\n return;\n })\n .catch(function(error) {\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return Notification.exception(error);\n });\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n },\n CONTENT_FORMATS: CONTENT_FORMATS\n };\n});\n"],"file":"inpage_reply.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/inpage_reply.js"],"names":["define","$","Templates","Notification","Repository","Selectors","DISPLAYCONSTANTS","MODERN","THREADED","NESTED","FLAT_OLDEST_FIRST","FLAT_NEWEST_FIRST","EVENTS","POST_CREATED","CONTENT_FORMATS","MOODLE","showSubmitButtonLoadingIcon","button","textContainer","find","post","inpageSubmitBtnText","loadingIconContainer","width","outerWidth","css","addClass","removeClass","hideSubmitButtonLoadingIcon","registerEventListeners","root","on","inpageSubmitBtn","e","preventDefault","submitButton","currentTarget","allButtons","parent","inpageReplyButton","form","parents","inpageReplyForm","get","message","elements","value","trim","messageformat","postid","reply","subject","currentRoot","closest","isprivatereply","privatereply","checked","modeSelector","modeSelect","mode","length","parseInt","newid","prop","addDiscussionPost","then","context","messages","reduce","carry","type","addNotification","reset","id","capabilities","showactionmenu","controlreadstatus","edit","split","delete","export","urls","viewparent","render","html","js","repliesnode","repliesContainer","first","prependNodeContents","appendNodeContents","trigger","inpageReplyContent","hide","location","href","catch","error","exception","init"],"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 in page replying to forum posts.\n *\n * @module mod_forum/inpage_reply\n * @package mod_forum\n * @copyright 2019 Peter Dias\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'mod_forum/repository',\n 'mod_forum/selectors',\n ], function(\n $,\n Templates,\n Notification,\n Repository,\n Selectors\n ) {\n\n var DISPLAYCONSTANTS = {\n MODERN: 4,\n THREADED: 2,\n NESTED: 3,\n FLAT_OLDEST_FIRST: 1,\n FLAT_NEWEST_FIRST: -1\n };\n\n var EVENTS = {\n POST_CREATED: 'mod_forum-post-created'\n };\n\n /**\n * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.\n * @type {Object}\n */\n var CONTENT_FORMATS = {\n MOODLE: 0\n };\n /**\n * Show the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var showSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n var width = button.outerWidth();\n // Fix the width so that the button size doesn't change when we show the loading icon.\n button.css('width', width);\n textContainer.addClass('hidden');\n loadingIconContainer.removeClass('hidden');\n };\n\n /**\n * Hide the loading icon for the submit button.\n *\n * @param {Object} button The submit button element\n */\n var hideSubmitButtonLoadingIcon = function(button) {\n var textContainer = button.find(Selectors.post.inpageSubmitBtnText);\n var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);\n // Reset the width back to it's default.\n button.css('width', '');\n textContainer.removeClass('hidden');\n loadingIconContainer.addClass('hidden');\n };\n\n /**\n * Register the event listeners for the submit button of the in page reply.\n *\n * @param {Object} root The discussion container element.\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.post.inpageSubmitBtn, function(e) {\n e.preventDefault();\n var submitButton = $(e.currentTarget);\n var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);\n var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);\n var message = form.elements.post.value.trim();\n // For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).\n // In the future, other formats should be supported, letting users to use their preferred editor and format.\n var messageformat = CONTENT_FORMATS.MOODLE;\n // The message post will be converted from messageformat to FORMAT_HTML.\n var topreferredformat = true;\n var postid = form.elements.reply.value;\n var subject = form.elements.subject.value;\n var currentRoot = submitButton.closest(Selectors.post.post);\n var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;\n var modeSelector = root.find(Selectors.post.modeSelect);\n var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;\n var newid;\n\n if (message.length) {\n showSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', true);\n\n Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)\n .then(function(context) {\n var message = context.messages.reduce(function(carry, message) {\n if (message.type == 'success') {\n carry += '

' + message.message + '

';\n }\n return carry;\n }, '');\n Notification.addNotification({\n message: message,\n type: \"success\"\n });\n\n return context;\n })\n .then(function(context) {\n form.reset();\n var post = context.post;\n newid = post.id;\n\n switch (mode) {\n case DISPLAYCONSTANTS.MODERN:\n var capabilities = post.capabilities;\n post.showactionmenu = capabilities.controlreadstatus ||\n capabilities.edit ||\n capabilities.split ||\n capabilities.delete ||\n capabilities.export ||\n post.urls.viewparent;\n return Templates.render('mod_forum/forum_discussion_modern_post_reply', post);\n case DISPLAYCONSTANTS.THREADED:\n return Templates.render('mod_forum/forum_discussion_threaded_post', post);\n case DISPLAYCONSTANTS.NESTED:\n return Templates.render('mod_forum/forum_discussion_nested_post', post);\n default:\n return Templates.render('mod_forum/forum_discussion_post', post);\n }\n })\n .then(function(html, js) {\n var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();\n\n if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {\n return Templates.prependNodeContents(repliesnode, html, js);\n } else {\n return Templates.appendNodeContents(repliesnode, html, js);\n }\n })\n .then(function() {\n submitButton.trigger(EVENTS.POST_CREATED, newid);\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return currentRoot.find(Selectors.post.inpageReplyContent).hide();\n })\n .then(function() {\n location.href = \"#p\" + newid;\n return;\n })\n .catch(function(error) {\n hideSubmitButtonLoadingIcon(submitButton);\n allButtons.prop('disabled', false);\n return Notification.exception(error);\n });\n }\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n },\n CONTENT_FORMATS: CONTENT_FORMATS,\n EVENTS: EVENTS\n };\n});\n"],"file":"inpage_reply.min.js"} \ No newline at end of file diff --git a/mod/forum/amd/build/selectors.min.js b/mod/forum/amd/build/selectors.min.js index 777f585f8b8..f1c788b34a6 100644 --- a/mod/forum/amd/build/selectors.min.js +++ b/mod/forum/amd/build/selectors.min.js @@ -1,2 +1,2 @@ -define ("mod_forum/selectors",[],function(){return{subscription:{toggle:"[data-type='subscription-toggle'][data-action='toggle']"},summary:{actions:"[data-container='discussion-summary-actions']"},post:{post:"[data-region=\"post\"]",action:"[data-region=\"post-action\"]",actionsContainer:"[data-region=\"post-actions-container\"]",authorName:"[data-region=\"author-name\"]",forumCoreContent:"[data-region-content='forum-post-core']",forumContent:"[data-content='forum-post']",forumSubject:"[data-region-content='forum-post-core-subject']",inpageReplyButton:"button",inpageReplyLink:"[data-action='collapsible-link']",inpageReplyCancelButton:"[data-action='cancel-inpage-reply']",inpageReplyCreateButton:"[data-action='create-inpage-reply']",inpageReplyContainer:"[data-region=\"inpage-reply-container\"]",inpageReplyContent:"[data-content='inpage-reply-content']",inpageReplyForm:"form[data-content='inpage-reply-form']",inpageSubmitBtn:"[data-action='forum-inpage-submit']",inpageSubmitBtnText:"[data-region='submit-text']",loadingIconContainer:"[data-region='loading-icon-container']",repliesContainer:"[data-region='replies-container']",modeSelect:"select[name='mode']"},lock:{toggle:"[data-action='toggle'][data-type='lock-toggle']",icon:"[data-region='locked-icon']"},favourite:{toggle:"[data-type='favorite-toggle'][data-action='toggle']"},pin:{toggle:"[data-type='pin-toggle'][data-action='toggle']"}}}); +define ("mod_forum/selectors",[],function(){return{subscription:{toggle:"[data-type='subscription-toggle'][data-action='toggle']"},summary:{actions:"[data-container='discussion-summary-actions']"},post:{post:"[data-region=\"post\"]",action:"[data-region=\"post-action\"]",actionsContainer:"[data-region=\"post-actions-container\"]",authorName:"[data-region=\"author-name\"]",forumCoreContent:"[data-region-content='forum-post-core']",forumContent:"[data-content='forum-post']",forumSubject:"[data-region-content='forum-post-core-subject']",inpageReplyButton:"button",inpageReplyLink:"[data-action='collapsible-link']",inpageReplyCancelButton:"[data-action='cancel-inpage-reply']",inpageReplyCreateButton:"[data-action='create-inpage-reply']",inpageReplyContainer:"[data-region=\"inpage-reply-container\"]",inpageReplyContent:"[data-content='inpage-reply-content']",inpageReplyForm:"form[data-content='inpage-reply-form']",inpageSubmitBtn:"[data-action='forum-inpage-submit']",inpageSubmitBtnText:"[data-region='submit-text']",loadingIconContainer:"[data-region='loading-icon-container']",repliesContainer:"[data-region='replies-container']",replyCount:"[data-region=\"reply-count\"]",modeSelect:"select[name='mode']",showReplies:"[data-action=\"show-replies\"]",hideReplies:"[data-action=\"hide-replies\"]",repliesVisibilityToggleContainer:"[data-region=\"replies-visibility-toggle-container\"]"},lock:{toggle:"[data-action='toggle'][data-type='lock-toggle']",icon:"[data-region='locked-icon']"},favourite:{toggle:"[data-type='favorite-toggle'][data-action='toggle']"},pin:{toggle:"[data-type='pin-toggle'][data-action='toggle']"},discussion:{tools:"[data-container=\"discussion-tools\"]"}}}); //# sourceMappingURL=selectors.min.js.map diff --git a/mod/forum/amd/build/selectors.min.js.map b/mod/forum/amd/build/selectors.min.js.map index 89f36caf74c..2a4d3af522d 100644 --- a/mod/forum/amd/build/selectors.min.js.map +++ b/mod/forum/amd/build/selectors.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/selectors.js"],"names":["define","subscription","toggle","summary","actions","post","action","actionsContainer","authorName","forumCoreContent","forumContent","forumSubject","inpageReplyButton","inpageReplyLink","inpageReplyCancelButton","inpageReplyCreateButton","inpageReplyContainer","inpageReplyContent","inpageReplyForm","inpageSubmitBtn","inpageSubmitBtnText","loadingIconContainer","repliesContainer","modeSelect","lock","icon","favourite","pin"],"mappings":"AAuBAA,OAAM,uBAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CACHC,YAAY,CAAE,CACVC,MAAM,CAAE,yDADE,CADX,CAIHC,OAAO,CAAE,CACLC,OAAO,CAAE,+CADJ,CAJN,CAOHC,IAAI,CAAE,CACFA,IAAI,CAAE,wBADJ,CAEFC,MAAM,CAAE,+BAFN,CAGFC,gBAAgB,CAAE,0CAHhB,CAIFC,UAAU,CAAE,+BAJV,CAKFC,gBAAgB,CAAE,yCALhB,CAMFC,YAAY,CAAE,6BANZ,CAOFC,YAAY,CAAE,iDAPZ,CAQFC,iBAAiB,CAAE,QARjB,CASFC,eAAe,CAAE,kCATf,CAUFC,uBAAuB,CAAE,qCAVvB,CAWFC,uBAAuB,CAAE,qCAXvB,CAYFC,oBAAoB,CAAE,0CAZpB,CAaFC,kBAAkB,CAAE,uCAblB,CAcFC,eAAe,CAAE,wCAdf,CAeFC,eAAe,CAAE,qCAff,CAgBFC,mBAAmB,CAAE,6BAhBnB,CAiBFC,oBAAoB,CAAE,wCAjBpB,CAkBFC,gBAAgB,CAAE,mCAlBhB,CAmBFC,UAAU,CAAE,qBAnBV,CAPH,CA4BHC,IAAI,CAAE,CACFtB,MAAM,CAAE,iDADN,CAEFuB,IAAI,CAAE,6BAFJ,CA5BH,CAgCHC,SAAS,CAAE,CACPxB,MAAM,CAAE,qDADD,CAhCR,CAmCHyB,GAAG,CAAE,CACDzB,MAAM,CAAE,gDADP,CAnCF,CAuCV,CAxCK,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 * Common CSS selectors for the forum UI.\n *\n * @module mod_forum/selectors\n * @package mod_forum\n * @copyright 2019 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n subscription: {\n toggle: \"[data-type='subscription-toggle'][data-action='toggle']\",\n },\n summary: {\n actions: \"[data-container='discussion-summary-actions']\"\n },\n post: {\n post: '[data-region=\"post\"]',\n action: '[data-region=\"post-action\"]',\n actionsContainer: '[data-region=\"post-actions-container\"]',\n authorName: '[data-region=\"author-name\"]',\n forumCoreContent: \"[data-region-content='forum-post-core']\",\n forumContent: \"[data-content='forum-post']\",\n forumSubject: \"[data-region-content='forum-post-core-subject']\",\n inpageReplyButton: \"button\",\n inpageReplyLink: \"[data-action='collapsible-link']\",\n inpageReplyCancelButton: \"[data-action='cancel-inpage-reply']\",\n inpageReplyCreateButton: \"[data-action='create-inpage-reply']\",\n inpageReplyContainer: '[data-region=\"inpage-reply-container\"]',\n inpageReplyContent: \"[data-content='inpage-reply-content']\",\n inpageReplyForm: \"form[data-content='inpage-reply-form']\",\n inpageSubmitBtn: \"[data-action='forum-inpage-submit']\",\n inpageSubmitBtnText: \"[data-region='submit-text']\",\n loadingIconContainer: \"[data-region='loading-icon-container']\",\n repliesContainer: \"[data-region='replies-container']\",\n modeSelect: \"select[name='mode']\"\n },\n lock: {\n toggle: \"[data-action='toggle'][data-type='lock-toggle']\",\n icon: \"[data-region='locked-icon']\"\n },\n favourite: {\n toggle: \"[data-type='favorite-toggle'][data-action='toggle']\",\n },\n pin: {\n toggle: \"[data-type='pin-toggle'][data-action='toggle']\",\n },\n };\n});\n"],"file":"selectors.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/selectors.js"],"names":["define","subscription","toggle","summary","actions","post","action","actionsContainer","authorName","forumCoreContent","forumContent","forumSubject","inpageReplyButton","inpageReplyLink","inpageReplyCancelButton","inpageReplyCreateButton","inpageReplyContainer","inpageReplyContent","inpageReplyForm","inpageSubmitBtn","inpageSubmitBtnText","loadingIconContainer","repliesContainer","replyCount","modeSelect","showReplies","hideReplies","repliesVisibilityToggleContainer","lock","icon","favourite","pin","discussion","tools"],"mappings":"AAuBAA,OAAM,uBAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CACHC,YAAY,CAAE,CACVC,MAAM,CAAE,yDADE,CADX,CAIHC,OAAO,CAAE,CACLC,OAAO,CAAE,+CADJ,CAJN,CAOHC,IAAI,CAAE,CACFA,IAAI,CAAE,wBADJ,CAEFC,MAAM,CAAE,+BAFN,CAGFC,gBAAgB,CAAE,0CAHhB,CAIFC,UAAU,CAAE,+BAJV,CAKFC,gBAAgB,CAAE,yCALhB,CAMFC,YAAY,CAAE,6BANZ,CAOFC,YAAY,CAAE,iDAPZ,CAQFC,iBAAiB,CAAE,QARjB,CASFC,eAAe,CAAE,kCATf,CAUFC,uBAAuB,CAAE,qCAVvB,CAWFC,uBAAuB,CAAE,qCAXvB,CAYFC,oBAAoB,CAAE,0CAZpB,CAaFC,kBAAkB,CAAE,uCAblB,CAcFC,eAAe,CAAE,wCAdf,CAeFC,eAAe,CAAE,qCAff,CAgBFC,mBAAmB,CAAE,6BAhBnB,CAiBFC,oBAAoB,CAAE,wCAjBpB,CAkBFC,gBAAgB,CAAE,mCAlBhB,CAmBFC,UAAU,CAAE,+BAnBV,CAoBFC,UAAU,CAAE,qBApBV,CAqBFC,WAAW,CAAE,gCArBX,CAsBFC,WAAW,CAAE,gCAtBX,CAuBFC,gCAAgC,CAAE,uDAvBhC,CAPH,CAgCHC,IAAI,CAAE,CACF1B,MAAM,CAAE,iDADN,CAEF2B,IAAI,CAAE,6BAFJ,CAhCH,CAoCHC,SAAS,CAAE,CACP5B,MAAM,CAAE,qDADD,CApCR,CAuCH6B,GAAG,CAAE,CACD7B,MAAM,CAAE,gDADP,CAvCF,CA0CH8B,UAAU,CAAE,CACRC,KAAK,CAAE,uCADC,CA1CT,CA8CV,CA/CK,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 * Common CSS selectors for the forum UI.\n *\n * @module mod_forum/selectors\n * @package mod_forum\n * @copyright 2019 Andrew Nicols \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n subscription: {\n toggle: \"[data-type='subscription-toggle'][data-action='toggle']\",\n },\n summary: {\n actions: \"[data-container='discussion-summary-actions']\"\n },\n post: {\n post: '[data-region=\"post\"]',\n action: '[data-region=\"post-action\"]',\n actionsContainer: '[data-region=\"post-actions-container\"]',\n authorName: '[data-region=\"author-name\"]',\n forumCoreContent: \"[data-region-content='forum-post-core']\",\n forumContent: \"[data-content='forum-post']\",\n forumSubject: \"[data-region-content='forum-post-core-subject']\",\n inpageReplyButton: \"button\",\n inpageReplyLink: \"[data-action='collapsible-link']\",\n inpageReplyCancelButton: \"[data-action='cancel-inpage-reply']\",\n inpageReplyCreateButton: \"[data-action='create-inpage-reply']\",\n inpageReplyContainer: '[data-region=\"inpage-reply-container\"]',\n inpageReplyContent: \"[data-content='inpage-reply-content']\",\n inpageReplyForm: \"form[data-content='inpage-reply-form']\",\n inpageSubmitBtn: \"[data-action='forum-inpage-submit']\",\n inpageSubmitBtnText: \"[data-region='submit-text']\",\n loadingIconContainer: \"[data-region='loading-icon-container']\",\n repliesContainer: \"[data-region='replies-container']\",\n replyCount: '[data-region=\"reply-count\"]',\n modeSelect: \"select[name='mode']\",\n showReplies: '[data-action=\"show-replies\"]',\n hideReplies: '[data-action=\"hide-replies\"]',\n repliesVisibilityToggleContainer: '[data-region=\"replies-visibility-toggle-container\"]'\n },\n lock: {\n toggle: \"[data-action='toggle'][data-type='lock-toggle']\",\n icon: \"[data-region='locked-icon']\"\n },\n favourite: {\n toggle: \"[data-type='favorite-toggle'][data-action='toggle']\",\n },\n pin: {\n toggle: \"[data-type='pin-toggle'][data-action='toggle']\",\n },\n discussion: {\n tools: '[data-container=\"discussion-tools\"]'\n }\n };\n});\n"],"file":"selectors.min.js"} \ No newline at end of file diff --git a/mod/forum/amd/src/discussion_modern.js b/mod/forum/amd/src/discussion_modern.js index 1e71dcf47a3..b80bbbcf725 100644 --- a/mod/forum/amd/src/discussion_modern.js +++ b/mod/forum/amd/src/discussion_modern.js @@ -43,6 +43,27 @@ const getPostContainer = (element) => { return element.closest(Selectors.post.post); }; +/** + * Get the closest post container element from the given element. + * + * @param {Object} element jQuery element to search from + * @param {Number} id Id of the post to find. + * @return {Object} jQuery element + */ +const getPostContainerById = (element, id) => { + return element.find(`${Selectors.post.post}[data-post-id=${id}]`); +}; + +/** + * Get the parent post container elements from the given element. + * + * @param {Object} element jQuery element to search from + * @return {Object} jQuery element + */ +const getParentPostContainers = (element) => { + return element.parents(Selectors.post.post); +}; + /** * Get the post content container element from the post container element. * @@ -64,36 +85,210 @@ const getInPageReplyContainer = (postContainer) => { }; /** - * Show the in page reply form in the given in page reply container. The form - * display will be animated. + * Get the in page reply form element from the post container element. * - * @param {Object} inPageReplyContainer jQuery element for the in page reply container - * @param {Function} afterAnimationCallback Callback after animation completes + * @param {Object} postContainer jQuery element for the post container + * @return {Object} jQuery element */ -const showInPageReplyForm = (inPageReplyContainer, afterAnimationCallback) => { - const form = inPageReplyContainer.find(Selectors.post.inpageReplyContent); +const getInPageReplyForm = (postContainer) => { + return getInPageReplyContainer(postContainer).find(Selectors.post.inpageReplyContent); +}; - form.slideDown({ +/** + * Get the in page reply create (reply) button element from the post container element. + * + * @param {Object} postContainer jQuery element for the post container + * @return {Object} jQuery element + */ +const getInPageReplyCreateButton = (postContainer) => { + return getPostContentContainer(postContainer).find(Selectors.post.inpageReplyCreateButton); +}; + +/** + * Get the replies visibility toggle container (show/hide replies button container) element + * from the post container element. + * + * @param {Object} postContainer jQuery element for the post container + * @return {Object} jQuery element + */ +const getRepliesVisibilityToggleContainer = (postContainer) => { + return postContainer.children(Selectors.post.repliesVisibilityToggleContainer); +}; + +/** + * Get the replies container element from the post container element. + * + * @param {Object} postContainer jQuery element for the post container + * @return {Object} jQuery element + */ +const getRepliesContainer = (postContainer) => { + return postContainer.children(Selectors.post.repliesContainer); +}; + +/** + * Check if the post has any replies. + * + * @param {Object} postContainer jQuery element for the post container + * @return {Bool} + */ +const hasReplies = (postContainer) => { + return getRepliesContainer(postContainer).children().length > 0; +}; + +/** + * Get the show replies button element from the replies visibility toggle container element. + * + * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container + * @return {Object} jQuery element + */ +const getShowRepliesButton = (replyVisibilityToggleContainer) => { + return replyVisibilityToggleContainer.find(Selectors.post.showReplies); +}; + +/** + * Get the hide replies button element from the replies visibility toggle container element. + * + * @param {Object} replyVisibilityToggleContainer jQuery element for the toggle container + * @return {Object} jQuery element + */ +const getHideRepliesButton = (replyVisibilityToggleContainer) => { + return replyVisibilityToggleContainer.find(Selectors.post.hideReplies); +}; + +/** + * Check if the replies are visible. + * + * @param {Object} postContainer jQuery element for the post container + * @return {Bool} + */ +const repliesVisible = (postContainer) => { + const repliesContainer = getRepliesContainer(postContainer); + return repliesContainer.is(':visible'); +}; + +/** + * Show the post replies. + * + * @param {Object} postContainer jQuery element for the post container + * @param {Number|null} postIdToSee Id of the post to scroll into view (if any) + */ +const showReplies = (postContainer, postIdToSee = null) => { + const repliesContainer = getRepliesContainer(postContainer); + const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer); + const showButton = getShowRepliesButton(replyVisibilityToggleContainer); + const hideButton = getHideRepliesButton(replyVisibilityToggleContainer); + + showButton.addClass('hidden'); + hideButton.removeClass('hidden'); + + repliesContainer.slideDown({ duration: ANIMATION_DURATION, queue: false, - complete: afterAnimationCallback + complete: () => { + if (postIdToSee) { + const postContainerToSee = getPostContainerById(repliesContainer, postIdToSee); + if (postContainerToSee.length) { + postContainerToSee[0].scrollIntoView(); + } + } + } }).css('display', 'none').fadeIn(ANIMATION_DURATION); }; +/** + * Hide the post replies. + * + * @param {Object} postContainer jQuery element for the post container + */ +const hideReplies = (postContainer) => { + const repliesContainer = getRepliesContainer(postContainer); + const replyVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer); + const showButton = getShowRepliesButton(replyVisibilityToggleContainer); + const hideButton = getHideRepliesButton(replyVisibilityToggleContainer); + + showButton.removeClass('hidden'); + hideButton.addClass('hidden'); + + repliesContainer.slideUp({ + duration: ANIMATION_DURATION, + queue: false + }).fadeOut(ANIMATION_DURATION); +}; + +/** Variable to hold the showInPageReplyForm function after it's built. */ +let showInPageReplyForm = null; + +/** + * Build the showInPageReplyForm function with the given additional template context. + * + * @param {Object} additionalTemplateContext Additional render context for the in page reply template. + * @return {Function} + */ +const buildShowInPageReplyFormFunction = (additionalTemplateContext) => { + /** + * Show the in page reply form in the given in page reply container. The form + * display will be animated. + * + * @param {Object} postContainer jQuery element for the post container + */ + return async (postContainer) => { + + const inPageReplyContainer = getInPageReplyContainer(postContainer); + const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer); + const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer); + + if (!hasInPageReplyForm(inPageReplyContainer)) { + try { + const html = await renderInPageReplyTemplate(additionalTemplateContext, inPageReplyCreateButton, postContainer); + Templates.appendNodeContents(inPageReplyContainer, html, ''); + } catch (e) { + Notification.exception(e); + } + } + + inPageReplyCreateButton.fadeOut(ANIMATION_DURATION, () => { + const inPageReplyForm = getInPageReplyForm(postContainer); + inPageReplyForm.slideDown({ + duration: ANIMATION_DURATION, + queue: false, + complete: () => { + inPageReplyForm.find('textarea').focus(); + } + }).css('display', 'none').fadeIn(ANIMATION_DURATION); + + if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) { + repliesVisibilityToggleContainer.fadeIn(ANIMATION_DURATION); + hideReplies(postContainer); + } + }); + }; +}; + /** * Hide the in page reply form in the given in page reply container. The form * display will be animated. * - * @param {Object} inPageReplyContainer jQuery element for the in page reply container - * @param {Function} afterAnimationCallback Callback after animation completes + * @param {Object} postContainer jQuery element for the post container + * @param {Number|null} postIdToSee Id of the post to scroll into view (if any) */ -const hideInPageReplyForm = (inPageReplyContainer, afterAnimationCallback) => { - const form = inPageReplyContainer.find(Selectors.post.inpageReplyContent); +const hideInPageReplyForm = (postContainer, postIdToSee = null) => { + const inPageReplyForm = getInPageReplyForm(postContainer); + const inPageReplyCreateButton = getInPageReplyCreateButton(postContainer); + const repliesVisibilityToggleContainer = getRepliesVisibilityToggleContainer(postContainer); - form.slideUp({ + if (repliesVisibilityToggleContainer.length && hasReplies(postContainer)) { + repliesVisibilityToggleContainer.fadeOut(ANIMATION_DURATION); + if (!repliesVisible(postContainer)) { + showReplies(postContainer, postIdToSee); + } + } + + inPageReplyForm.slideUp({ duration: ANIMATION_DURATION, queue: false, - complete: afterAnimationCallback + complete: () => { + inPageReplyCreateButton.fadeIn(ANIMATION_DURATION); + } }).fadeOut(200); }; @@ -133,52 +328,65 @@ const renderInPageReplyTemplate = (additionalTemplateContext, button, postContai return Templates.render('mod_forum/inpage_reply_modern', context); }; +/** + * Increment the total reply count in the show/hide replies buttons for the post. + * + * @param {Object} postContainer jQuery element for the post container + */ +const incrementTotalReplyCount = (postContainer) => { + getRepliesVisibilityToggleContainer(postContainer).find(Selectors.post.replyCount).each((index, element) => { + const currentCount = parseInt(element.innerText, 10); + element.innerText = currentCount + 1; + }); +}; + /** * Create all of the event listeners for the discussion. * * @param {Object} root jQuery element for the discussion container - * @param {Object} additionalTemplateContext Additional render context for the in page reply template */ -const registerEventListeners = (root, additionalTemplateContext) => { +const registerEventListeners = (root) => { CustomEvents.define(root, [CustomEvents.events.activate]); // Auto expanding text area for in page reply. AutoRows.init(root); // Reply button is clicked. - root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, async (e, data) => { + root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCreateButton, (e, data) => { data.originalEvent.preventDefault(); - - const button = $(e.currentTarget); - const postContainer = getPostContainer(button); - const inPageReplyContainer = getInPageReplyContainer(postContainer); - - if (!hasInPageReplyForm(inPageReplyContainer)) { - try { - const html = await renderInPageReplyTemplate(additionalTemplateContext, button, postContainer); - Templates.appendNodeContents(inPageReplyContainer, html, ''); - } catch (e) { - Notification.exception(e); - } - } - - button.fadeOut(ANIMATION_DURATION, () => { - showInPageReplyForm(inPageReplyContainer, () => { - inPageReplyContainer.find(Selectors.post.inpageReplyContent).find('textarea').focus(); - }); - }); + const postContainer = getPostContainer($(e.currentTarget)); + showInPageReplyForm(postContainer); }); // Cancel in page reply button. root.on(CustomEvents.events.activate, Selectors.post.inpageReplyCancelButton, (e, data) => { data.originalEvent.preventDefault(); + const postContainer = getPostContainer($(e.currentTarget)); + hideInPageReplyForm(postContainer); + }); - const button = $(e.currentTarget); - const postContainer = getPostContainer(button); - const postContentContainer = getPostContentContainer(postContainer); - const inPageReplyContainer = getInPageReplyContainer(postContainer); - const inPageReplyCreateButton = postContentContainer.find(Selectors.post.inpageReplyCreateButton); - hideInPageReplyForm(inPageReplyContainer, () => { - inPageReplyCreateButton.fadeIn(ANIMATION_DURATION); + // Show replies button clicked. + root.on(CustomEvents.events.activate, Selectors.post.showReplies, (e, data) => { + data.originalEvent.preventDefault(); + const postContainer = getPostContainer($(e.target)); + showReplies(postContainer); + }); + + // Hide replies button clicked. + root.on(CustomEvents.events.activate, Selectors.post.hideReplies, (e, data) => { + data.originalEvent.preventDefault(); + const postContainer = getPostContainer($(e.target)); + hideReplies(postContainer); + }); + + // Post created with in page reply. + root.on(InPageReply.EVENTS.POST_CREATED, Selectors.post.inpageSubmitBtn, (e, newPostId) => { + const currentTarget = $(e.currentTarget); + const postContainer = getPostContainer(currentTarget); + const postContainers = getParentPostContainers(currentTarget); + hideInPageReplyForm(postContainer, newPostId); + + postContainers.each((index, container) => { + incrementTotalReplyCount($(container)); }); }); }; @@ -190,15 +398,17 @@ const registerEventListeners = (root, additionalTemplateContext) => { * @param {Object} context Additional render context for the in page reply template */ export const init = (root, context) => { + // Build the showInPageReplyForm function with the additional render context. + showInPageReplyForm = buildShowInPageReplyFormFunction(context); // Add discussion event listeners. - registerEventListeners(root, context); - // Add default discussion javascript (keyboard nav etc). + registerEventListeners(root); + // Initialise default discussion javascript (keyboard nav etc). Discussion.init(root); // Add in page reply javascript. InPageReply.init(root); // Initialise the settings menu javascript. - const discussionToolsContainer = root.find('[data-container="discussion-tools"]'); + const discussionToolsContainer = root.find(Selectors.discussion.tools); LockToggle.init(discussionToolsContainer); FavouriteToggle.init(discussionToolsContainer); Pin.init(discussionToolsContainer); diff --git a/mod/forum/amd/src/inpage_reply.js b/mod/forum/amd/src/inpage_reply.js index 3646dbc1499..98625d83c84 100644 --- a/mod/forum/amd/src/inpage_reply.js +++ b/mod/forum/amd/src/inpage_reply.js @@ -43,6 +43,10 @@ define([ FLAT_NEWEST_FIRST: -1 }; + var EVENTS = { + POST_CREATED: 'mod_forum-post-created' + }; + /** * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php. * @type {Object} @@ -156,6 +160,7 @@ define([ } }) .then(function() { + submitButton.trigger(EVENTS.POST_CREATED, newid); hideSubmitButtonLoadingIcon(submitButton); allButtons.prop('disabled', false); return currentRoot.find(Selectors.post.inpageReplyContent).hide(); @@ -177,6 +182,7 @@ define([ init: function(root) { registerEventListeners(root); }, - CONTENT_FORMATS: CONTENT_FORMATS + CONTENT_FORMATS: CONTENT_FORMATS, + EVENTS: EVENTS }; }); diff --git a/mod/forum/amd/src/selectors.js b/mod/forum/amd/src/selectors.js index baf62df696d..258652b14cc 100644 --- a/mod/forum/amd/src/selectors.js +++ b/mod/forum/amd/src/selectors.js @@ -48,7 +48,11 @@ define([], function() { inpageSubmitBtnText: "[data-region='submit-text']", loadingIconContainer: "[data-region='loading-icon-container']", repliesContainer: "[data-region='replies-container']", - modeSelect: "select[name='mode']" + replyCount: '[data-region="reply-count"]', + modeSelect: "select[name='mode']", + showReplies: '[data-action="show-replies"]', + hideReplies: '[data-action="hide-replies"]', + repliesVisibilityToggleContainer: '[data-region="replies-visibility-toggle-container"]' }, lock: { toggle: "[data-action='toggle'][data-type='lock-toggle']", @@ -60,5 +64,8 @@ define([], function() { pin: { toggle: "[data-type='pin-toggle'][data-action='toggle']", }, + discussion: { + tools: '[data-container="discussion-tools"]' + } }; }); diff --git a/mod/forum/lang/en/forum.php b/mod/forum/lang/en/forum.php index 84d75977db3..71c312f3568 100644 --- a/mod/forum/lang/en/forum.php +++ b/mod/forum/lang/en/forum.php @@ -311,6 +311,7 @@ $string['forum:viewsubscribers'] = 'View subscribers'; $string['generalforum'] = 'Standard forum for general use'; $string['generalforums'] = 'General forums'; $string['hiddenforumpost'] = 'Hidden forum post'; +$string['hidepreviousrepliescount'] = 'Hide previous replies ({$a})'; $string['indicator:cognitivedepth'] = 'Forum cognitive'; $string['indicator:cognitivedepth_help'] = 'This indicator is based on the cognitive depth reached by the student in a Forum activity.'; $string['indicator:socialbreadth'] = 'Forum social'; @@ -598,6 +599,7 @@ $string['seeallposts'] = 'See all posts made by this user'; $string['settings'] = 'Settings'; $string['shortpost'] = 'Short post'; $string['showingcountoftotaldiscussions'] = 'Showing {$a->count} of {$a->total} discussions'; +$string['showpreviousrepliescount'] = 'Show previous replies ({$a})'; $string['showsubscribers'] = 'Show/edit current subscribers'; $string['singleforum'] = 'A single simple discussion'; $string['smallmessage'] = '{$a->user} posted in {$a->forumname}'; diff --git a/mod/forum/templates/forum_discussion_modern_post_reply.mustache b/mod/forum/templates/forum_discussion_modern_post_reply.mustache index 100789f4078..0d7209fe609 100644 --- a/mod/forum/templates/forum_discussion_modern_post_reply.mustache +++ b/mod/forum/templates/forum_discussion_modern_post_reply.mustache @@ -53,6 +53,22 @@ {{/isdeleted}} {{/footer}} {{$replies}} +
{{#hasreplies}} {{#replies}}