mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 16:32:18 +02:00
MDL-64821 mod_forum: add show/hide reply toggle for modern view
This commit is contained in:
parent
38d96b6540
commit
7902e4dc55
2
mod/forum/amd/build/discussion_modern.min.js
vendored
2
mod/forum/amd/build/discussion_modern.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
mod/forum/amd/build/inpage_reply.min.js
vendored
2
mod/forum/amd/build/inpage_reply.min.js
vendored
@ -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+="<p>"+b.message+"</p>"}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+="<p>"+b.message+"</p>"}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
|
||||
|
File diff suppressed because one or more lines are too long
2
mod/forum/amd/build/selectors.min.js
vendored
2
mod/forum/amd/build/selectors.min.js
vendored
@ -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
|
||||
|
@ -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 <http://www.gnu.org/licenses/>.\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 <andrew@nicols.co.uk>\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"}
|
||||
{"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 <http://www.gnu.org/licenses/>.\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 <andrew@nicols.co.uk>\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"}
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
});
|
||||
|
@ -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"]'
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -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}';
|
||||
|
@ -53,6 +53,22 @@
|
||||
{{/isdeleted}}
|
||||
{{/footer}}
|
||||
{{$replies}}
|
||||
<div class="indent my-4" data-region="replies-visibility-toggle-container" style="display: none">
|
||||
<button class="btn btn-link pl-0" data-action="show-replies">
|
||||
{{#str}}
|
||||
showpreviousrepliescount,
|
||||
mod_forum,
|
||||
<span data-region="reply-count">{{#totalreplycount}}{{.}}{{/totalreplycount}}{{^totalreplycount}}0{{/totalreplycount}}</span>
|
||||
{{/str}}
|
||||
</button>
|
||||
<button class="btn btn-link hidden pl-0" data-action="hide-replies">
|
||||
{{#str}}
|
||||
hidepreviousrepliescount,
|
||||
mod_forum,
|
||||
<span data-region="reply-count">{{#totalreplycount}}{{.}}{{/totalreplycount}}{{^totalreplycount}}0{{/totalreplycount}}</span>
|
||||
{{/str}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="indent replies-container" data-region="replies-container">
|
||||
{{#hasreplies}}
|
||||
{{#replies}}
|
||||
|
Loading…
x
Reference in New Issue
Block a user