Merge branch 'MDL-66481-master-6' of git://github.com/junpataleta/moodle

This commit is contained in:
Jake Dallimore 2019-09-26 11:57:51 +08:00
commit 57054fc66b
39 changed files with 518 additions and 691 deletions

View File

@ -37,8 +37,10 @@ $string['localewincharset'] = '';
$string['oldcharset'] = 'ISO-8859-1';
$string['parentlanguage'] = '';
$string['strftimedate'] = '%d %B %Y';
$string['strftimedatemonthabbr'] = '%d %b %Y';
$string['strftimedatefullshort'] = '%d/%m/%y';
$string['strftimedateshort'] = '%d %B';
$string['strftimedateshortmonthabbr'] = '%d %b';
$string['strftimedatetime'] = '%d %B %Y, %I:%M %p';
$string['strftimedatetimeshort'] = '%d/%m/%y, %H:%M';
$string['strftimedaydate'] = '%A, %d %B %Y';

View File

@ -1,2 +1,2 @@
define ("mod_forum/discussion",["jquery","core/custom_interaction_events","mod_forum/selectors"],function(a,b,c){var d=function(a){var b=a.prev(c.post.post);if(b.length){var d=b.find(c.post.post).last();if(d.length){d.focus()}else{b.focus()}}else{a.parents(c.post.post).first().focus()}},e=function(b){var d=b.find(c.post.post).first();if(d.length){d.focus()}else{var e=b.next(c.post.post);if(e.length){e.focus()}else{for(var f=b.parents(c.post.post).toArray(),g=0,h;g<f.length;g++){h=a(f[g]).next(c.post.post);if(h.length){h.focus();break}}}}},f=function(b){var d=a(b).closest(c.post.inpageReplyContent);return d.length?!0:!1},g=function(g){var h=g.find(c.post.post);h.each(function(b,d){var e=a(d).find(c.post.action),f=e.first();e.attr("tabindex","-1");f.attr("tabindex",0)});b.define(g,[b.events.up,b.events.down,b.events.next,b.events.previous,b.events.home,b.events.end]);g.on(b.events.up,function(b,e){var h=document.activeElement;if(f(h)){return}var i=a(h).closest(c.post.post);if(i.length){d(i)}else{g.find(c.post.post).first().focus()}e.originalEvent.preventDefault()});g.on(b.events.down,function(b,d){var h=document.activeElement;if(f(h)){return}var i=a(h).closest(c.post.post);if(i.length){e(i)}else{g.find(c.post.post).first().focus()}d.originalEvent.preventDefault()});g.on(b.events.home,function(a,b){if(f(document.activeElement)){return}g.find(c.post.post).first().focus();b.originalEvent.preventDefault()});g.on(b.events.end,function(a,b){if(f(document.activeElement)){return}g.find(c.post.post).last().focus();b.originalEvent.preventDefault()});g.on(b.events.next,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=e.next(c.post.action);g.attr("tabindex","-1");if(!h.length){h=g.first()}h.attr("tabindex",0);h.focus();d.originalEvent.preventDefault()});g.on(b.events.previous,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=e.prev(c.post.action);g.attr("tabindex","-1");if(!h.length){h=g.last()}h.attr("tabindex",0);h.focus();d.originalEvent.preventDefault()});g.on(b.events.home,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=g.first();g.attr("tabindex","-1");h.attr("tabindex",0);h.focus();b.stopPropagation();d.originalEvent.preventDefault()});g.on(b.events.end,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=g.last();g.attr("tabindex","-1");h.attr("tabindex",0);h.focus();b.stopPropagation();d.originalEvent.preventDefault()})};return{init:function init(a){g(a)}}});
define ("mod_forum/discussion",["jquery","core/custom_interaction_events","mod_forum/selectors","core/pubsub","mod_forum/forum_events","core/str","core/notification"],function(a,b,c,d,e,f,g){var h=function(a){var b=a.prev(c.post.post);if(b.length){var d=b.find(c.post.post).last();if(d.length){d.focus()}else{b.focus()}}else{a.parents(c.post.post).first().focus()}},i=function(b){var d=b.find(c.post.post).first();if(d.length){d.focus()}else{var e=b.next(c.post.post);if(e.length){e.focus()}else{for(var f=b.parents(c.post.post).toArray(),g=0,h;g<f.length;g++){h=a(f[g]).next(c.post.post);if(h.length){h.focus();break}}}}},j=function(b){var d=a(b).closest(c.post.inpageReplyContent);return d.length?!0:!1},k=function(k){var l=k.find(c.post.post);l.each(function(b,d){var e=a(d).find(c.post.action),f=e.first();e.attr("tabindex","-1");f.attr("tabindex",0)});b.define(k,[b.events.up,b.events.down,b.events.next,b.events.previous,b.events.home,b.events.end]);k.on(b.events.up,function(b,d){var e=document.activeElement;if(j(e)){return}var f=a(e).closest(c.post.post);if(f.length){h(f)}else{k.find(c.post.post).first().focus()}d.originalEvent.preventDefault()});k.on(b.events.down,function(b,d){var e=document.activeElement;if(j(e)){return}var f=a(e).closest(c.post.post);if(f.length){i(f)}else{k.find(c.post.post).first().focus()}d.originalEvent.preventDefault()});k.on(b.events.home,function(a,b){if(j(document.activeElement)){return}k.find(c.post.post).first().focus();b.originalEvent.preventDefault()});k.on(b.events.end,function(a,b){if(j(document.activeElement)){return}k.find(c.post.post).last().focus();b.originalEvent.preventDefault()});k.on(b.events.next,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=e.next(c.post.action);g.attr("tabindex","-1");if(!h.length){h=g.first()}h.attr("tabindex",0);h.focus();d.originalEvent.preventDefault()});k.on(b.events.previous,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=e.prev(c.post.action);g.attr("tabindex","-1");if(!h.length){h=g.last()}h.attr("tabindex",0);h.focus();d.originalEvent.preventDefault()});k.on(b.events.home,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=g.first();g.attr("tabindex","-1");h.attr("tabindex",0);h.focus();b.stopPropagation();d.originalEvent.preventDefault()});k.on(b.events.end,c.post.action,function(b,d){var e=a(b.target),f=e.closest(c.post.actionsContainer),g=f.find(c.post.action),h=g.last();g.attr("tabindex","-1");h.attr("tabindex",0);h.focus();b.stopPropagation();d.originalEvent.preventDefault()});d.subscribe(e.SUBSCRIPTION_TOGGLED,function(a){var b=a.subscriptionState,c=b?"discussionsubscribed":"discussionunsubscribed";f.get_string(c,"forum").then(function(a){return g.addNotification({message:a,type:"info"})}).catch(g.exception)})};return{init:function init(a){k(a)}}});
//# sourceMappingURL=discussion.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("mod_forum/discussion_list",["jquery","core/templates","core/str","core/notification","mod_forum/subscription_toggle","mod_forum/selectors","mod_forum/repository"],function(a,b,c,d,e,f,g){var h=function(e){e.on("click",f.favourite.toggle,function(){var b=a(this),c=b.data("forumid"),e=b.data("discussionid"),f=b.data("targetstate");g.setFavouriteDiscussionState(c,e,f).then(function(){return location.reload()}).catch(d.exception)});e.on("click",f.pin.toggle,function(b){b.preventDefault();var c=a(this),e=c.data("forumid"),f=c.data("discussionid"),h=c.data("targetstate");g.setPinDiscussionState(e,f,h).then(function(){return location.reload()}).catch(d.exception)});e.on("click",f.lock.toggle,function(h){var e=a(this),i=e.data("forumid"),j=e.data("discussionid"),k=e.data("state");g.setDiscussionLockState(i,j,k).then(function(a){var b=e.parents(f.summary.actions).find(f.lock.icon);if(a.locked){b.removeClass("hidden")}else{b.addClass("hidden")}return a}).then(function(a){a.forumid=i;return b.render("mod_forum/discussion_lock_toggle",a)}).then(function(a,c){return b.replaceNode(e,a,c)}).then(function(){return c.get_string("lockupdated","forum").done(function(a){return d.addNotification({message:a,type:"info"})})}).catch(d.exception);h.preventDefault()})};return{init:function init(a){e.init(a);h(a)}}});
define ("mod_forum/discussion_list",["jquery","core/templates","core/str","core/notification","mod_forum/subscription_toggle","mod_forum/selectors","mod_forum/repository","core/pubsub","mod_forum/forum_events"],function(a,b,c,d,e,f,g,h,i){var j=function(e){h.subscribe(i.SUBSCRIPTION_TOGGLED,function(a){var b=a.discussionId,c=a.subscriptionState,d=e.find(f.discussion.item+"[data-discussionid= "+b+"] "+f.discussion.subscribedLabel);if(c){d.removeAttr("hidden")}else{d.attr("hidden",!0)}});e.on("click",f.favourite.toggle,function(){var b=a(this),c=b.data("forumid"),e=b.data("discussionid"),f=b.data("targetstate");g.setFavouriteDiscussionState(c,e,f).then(function(){return location.reload()}).catch(d.exception)});e.on("click",f.pin.toggle,function(b){b.preventDefault();var c=a(this),e=c.data("forumid"),f=c.data("discussionid"),h=c.data("targetstate");g.setPinDiscussionState(e,f,h).then(function(){return location.reload()}).catch(d.exception)});e.on("click",f.lock.toggle,function(h){var e=a(this),i=e.data("forumid"),j=e.data("discussionid"),k=e.data("state");g.setDiscussionLockState(i,j,k).then(function(a){var b=e.parents(f.summary.actions).find(f.lock.icon),c=e.parents(f.discussion.item).find(f.discussion.lockedLabel);if(a.locked){b.removeClass("hidden");c.removeAttr("hidden")}else{b.addClass("hidden");c.attr("hidden",!0)}return a}).then(function(a){a.forumid=i;return b.render("mod_forum/discussion_lock_toggle",a)}).then(function(a,c){return b.replaceNode(e,a,c)}).then(function(){return c.get_string("lockupdated","forum").done(function(a){return d.addNotification({message:a,type:"info"})})}).catch(d.exception);h.preventDefault()})};return{init:function init(a){e.init(a);j(a)}}});
//# sourceMappingURL=discussion_list.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
define ("mod_forum/forum_events",[],function(){return{SUBSCRIPTION_TOGGLED:"mod_forum/subscription_toggle:subscriptionToggled"}});
//# sourceMappingURL=forum_events.min.js.map

View File

@ -0,0 +1 @@
{"version":3,"sources":["../src/forum_events.js"],"names":["define","SUBSCRIPTION_TOGGLED"],"mappings":"AAuBAA,OAAM,0BAAC,EAAD,CAAK,UAAW,CAClB,MAAO,CACHC,oBAAoB,CAAE,mDADnB,CAGV,CAJK,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 * Events for the forum activity.\n *\n * @module mod_forum/forum_events\n * @package mod_forum\n * @copyright 2019 Jun Pataleta <jun@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n SUBSCRIPTION_TOGGLED: 'mod_forum/subscription_toggle:subscriptionToggled',\n };\n});\n"],"file":"forum_events.min.js"}

View File

@ -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']",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\"]"}}});
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\"]",item:"[data-region=\"discussion-list-item\"]",lockedLabel:"[data-region='locked-label']",subscribedLabel:"[data-region='subscribed-label']",timedLabel:"[data-region='timed-label']"}}});
//# sourceMappingURL=selectors.min.js.map

File diff suppressed because one or more lines are too long

View File

@ -1,2 +1,2 @@
define ("mod_forum/subscription_toggle",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,e){var f=function(f){f.on("click",e.subscription.toggle,function(f){var e=a(this),g=e.data("forumid"),h=e.data("discussionid"),i=e.data("targetstate");d.setDiscussionSubscriptionState(g,h,i).then(function(a){return b.render("mod_forum/discussion_subscription_toggle",a)}).then(function(a,c){return b.replaceNode(e,a,c)}).catch(c.exception);f.preventDefault()})};return{init:function init(a){f(a)}}});
define ("mod_forum/subscription_toggle",["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors","core/pubsub","mod_forum/forum_events"],function(a,b,c,d,e,f,g){var h=function(h){h.on("click",e.subscription.toggle,function(h){var e=a(this),i=e.data("forumid"),j=e.data("discussionid"),k=e.data("targetstate");d.setDiscussionSubscriptionState(i,j,k).then(function(a){f.publish(g.SUBSCRIPTION_TOGGLED,{discussionId:j,subscriptionState:k});return b.render("mod_forum/discussion_subscription_toggle",a)}).then(function(a,c){return b.replaceNode(e,a,c)}).catch(c.exception);h.preventDefault()})};return{init:function init(a){h(a)}}});
//# sourceMappingURL=subscription_toggle.min.js.map

View File

@ -1 +1 @@
{"version":3,"sources":["../src/subscription_toggle.js"],"names":["define","$","Templates","Notification","Repository","Selectors","registerEventListeners","root","on","subscription","toggle","e","toggleElement","forumId","data","discussionId","subscriptionState","setDiscussionSubscriptionState","then","context","render","html","js","replaceNode","catch","exception","preventDefault","init"],"mappings":"AAwBAA,OAAM,iCAAC,CACC,QADD,CAEC,gBAFD,CAGC,mBAHD,CAIC,sBAJD,CAKC,qBALD,CAAD,CAMC,SACCC,CADD,CAECC,CAFD,CAGCC,CAHD,CAICC,CAJD,CAKCC,CALD,CAMD,CAOF,GAAIC,CAAAA,CAAsB,CAAG,SAASC,CAAT,CAAe,CACxCA,CAAI,CAACC,EAAL,CAAQ,OAAR,CAAiBH,CAAS,CAACI,YAAV,CAAuBC,MAAxC,CAAgD,SAASC,CAAT,CAAY,IACpDC,CAAAA,CAAa,CAAGX,CAAC,CAAC,IAAD,CADmC,CAEpDY,CAAO,CAAGD,CAAa,CAACE,IAAd,CAAmB,SAAnB,CAF0C,CAGpDC,CAAY,CAAGH,CAAa,CAACE,IAAd,CAAmB,cAAnB,CAHqC,CAIpDE,CAAiB,CAAGJ,CAAa,CAACE,IAAd,CAAmB,aAAnB,CAJgC,CAMxDV,CAAU,CAACa,8BAAX,CAA0CJ,CAA1C,CAAmDE,CAAnD,CAAiEC,CAAjE,EACKE,IADL,CACU,SAASC,CAAT,CAAkB,CACpB,MAAOjB,CAAAA,CAAS,CAACkB,MAAV,CAAiB,0CAAjB,CAA6DD,CAA7D,CACV,CAHL,EAIKD,IAJL,CAIU,SAASG,CAAT,CAAeC,CAAf,CAAmB,CACrB,MAAOpB,CAAAA,CAAS,CAACqB,WAAV,CAAsBX,CAAtB,CAAqCS,CAArC,CAA2CC,CAA3C,CACV,CANL,EAOKE,KAPL,CAOWrB,CAAY,CAACsB,SAPxB,EASAd,CAAC,CAACe,cAAF,EACH,CAhBD,CAiBH,CAlBD,CAoBA,MAAO,CACHC,IAAI,CAAE,cAASpB,CAAT,CAAe,CACjBD,CAAsB,CAACC,CAAD,CACzB,CAHE,CAKV,CA5CK,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 * Handle discussion subscription toggling on a discussion list in\n * the forum view.\n *\n * @module mod_forum/subscription_toggle\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([\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 /**\n * Register event listeners for the subscription toggle.\n *\n * @param {object} root The discussion list root element\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.subscription.toggle, function(e) {\n var toggleElement = $(this);\n var forumId = toggleElement.data('forumid');\n var discussionId = toggleElement.data('discussionid');\n var subscriptionState = toggleElement.data('targetstate');\n\n Repository.setDiscussionSubscriptionState(forumId, discussionId, subscriptionState)\n .then(function(context) {\n return Templates.render('mod_forum/discussion_subscription_toggle', context);\n })\n .then(function(html, js) {\n return Templates.replaceNode(toggleElement, html, js);\n })\n .catch(Notification.exception);\n\n e.preventDefault();\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n }\n };\n});\n"],"file":"subscription_toggle.min.js"}
{"version":3,"sources":["../src/subscription_toggle.js"],"names":["define","$","Templates","Notification","Repository","Selectors","PubSub","ForumEvents","registerEventListeners","root","on","subscription","toggle","e","toggleElement","forumId","data","discussionId","subscriptionState","setDiscussionSubscriptionState","then","context","publish","SUBSCRIPTION_TOGGLED","render","html","js","replaceNode","catch","exception","preventDefault","init"],"mappings":"AAwBAA,OAAM,iCAAC,CACC,QADD,CAEC,gBAFD,CAGC,mBAHD,CAIC,sBAJD,CAKC,qBALD,CAMC,aAND,CAOC,wBAPD,CAAD,CAQC,SACCC,CADD,CAECC,CAFD,CAGCC,CAHD,CAICC,CAJD,CAKCC,CALD,CAMCC,CAND,CAOCC,CAPD,CAQD,CAOF,GAAIC,CAAAA,CAAsB,CAAG,SAASC,CAAT,CAAe,CACxCA,CAAI,CAACC,EAAL,CAAQ,OAAR,CAAiBL,CAAS,CAACM,YAAV,CAAuBC,MAAxC,CAAgD,SAASC,CAAT,CAAY,IACpDC,CAAAA,CAAa,CAAGb,CAAC,CAAC,IAAD,CADmC,CAEpDc,CAAO,CAAGD,CAAa,CAACE,IAAd,CAAmB,SAAnB,CAF0C,CAGpDC,CAAY,CAAGH,CAAa,CAACE,IAAd,CAAmB,cAAnB,CAHqC,CAIpDE,CAAiB,CAAGJ,CAAa,CAACE,IAAd,CAAmB,aAAnB,CAJgC,CAMxDZ,CAAU,CAACe,8BAAX,CAA0CJ,CAA1C,CAAmDE,CAAnD,CAAiEC,CAAjE,EACKE,IADL,CACU,SAASC,CAAT,CAAkB,CACpBf,CAAM,CAACgB,OAAP,CAAef,CAAW,CAACgB,oBAA3B,CAAiD,CAC7CN,YAAY,CAAEA,CAD+B,CAE7CC,iBAAiB,CAAEA,CAF0B,CAAjD,EAIA,MAAOhB,CAAAA,CAAS,CAACsB,MAAV,CAAiB,0CAAjB,CAA6DH,CAA7D,CACV,CAPL,EAQKD,IARL,CAQU,SAASK,CAAT,CAAeC,CAAf,CAAmB,CACrB,MAAOxB,CAAAA,CAAS,CAACyB,WAAV,CAAsBb,CAAtB,CAAqCW,CAArC,CAA2CC,CAA3C,CACV,CAVL,EAWKE,KAXL,CAWWzB,CAAY,CAAC0B,SAXxB,EAaAhB,CAAC,CAACiB,cAAF,EACH,CApBD,CAqBH,CAtBD,CAwBA,MAAO,CACHC,IAAI,CAAE,cAAStB,CAAT,CAAe,CACjBD,CAAsB,CAACC,CAAD,CACzB,CAHE,CAKV,CApDK,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 * Handle discussion subscription toggling on a discussion list in\n * the forum view.\n *\n * @module mod_forum/subscription_toggle\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([\n 'jquery',\n 'core/templates',\n 'core/notification',\n 'mod_forum/repository',\n 'mod_forum/selectors',\n 'core/pubsub',\n 'mod_forum/forum_events',\n ], function(\n $,\n Templates,\n Notification,\n Repository,\n Selectors,\n PubSub,\n ForumEvents\n ) {\n\n /**\n * Register event listeners for the subscription toggle.\n *\n * @param {object} root The discussion list root element\n */\n var registerEventListeners = function(root) {\n root.on('click', Selectors.subscription.toggle, function(e) {\n var toggleElement = $(this);\n var forumId = toggleElement.data('forumid');\n var discussionId = toggleElement.data('discussionid');\n var subscriptionState = toggleElement.data('targetstate');\n\n Repository.setDiscussionSubscriptionState(forumId, discussionId, subscriptionState)\n .then(function(context) {\n PubSub.publish(ForumEvents.SUBSCRIPTION_TOGGLED, {\n discussionId: discussionId,\n subscriptionState: subscriptionState\n });\n return Templates.render('mod_forum/discussion_subscription_toggle', context);\n })\n .then(function(html, js) {\n return Templates.replaceNode(toggleElement, html, js);\n })\n .catch(Notification.exception);\n\n e.preventDefault();\n });\n };\n\n return {\n init: function(root) {\n registerEventListeners(root);\n }\n };\n});\n"],"file":"subscription_toggle.min.js"}

View File

@ -25,12 +25,20 @@ define(
[
'jquery',
'core/custom_interaction_events',
'mod_forum/selectors'
'mod_forum/selectors',
'core/pubsub',
'mod_forum/forum_events',
'core/str',
'core/notification',
],
function(
$,
CustomEvents,
Selectors
Selectors,
PubSub,
ForumEvents,
String,
Notification
) {
/**
@ -261,6 +269,19 @@ function(
e.stopPropagation();
data.originalEvent.preventDefault();
});
PubSub.subscribe(ForumEvents.SUBSCRIPTION_TOGGLED, function(data) {
var subscribed = data.subscriptionState;
var updateMessage = subscribed ? 'discussionsubscribed' : 'discussionunsubscribed';
String.get_string(updateMessage, "forum")
.then(function(s) {
return Notification.addNotification({
message: s,
type: "info"
});
})
.catch(Notification.exception);
});
};
return {

View File

@ -29,6 +29,8 @@ define([
'mod_forum/subscription_toggle',
'mod_forum/selectors',
'mod_forum/repository',
'core/pubsub',
'mod_forum/forum_events',
], function(
$,
Templates,
@ -36,9 +38,23 @@ define([
Notification,
SubscriptionToggle,
Selectors,
Repository
Repository,
PubSub,
ForumEvents
) {
var registerEventListeners = function(root) {
PubSub.subscribe(ForumEvents.SUBSCRIPTION_TOGGLED, function(data) {
var discussionId = data.discussionId;
var subscribed = data.subscriptionState;
var subscribedLabel = root.find(Selectors.discussion.item + '[data-discussionid= ' + discussionId + '] '
+ Selectors.discussion.subscribedLabel);
if (subscribed) {
subscribedLabel.removeAttr('hidden');
} else {
subscribedLabel.attr('hidden', true);
}
});
root.on('click', Selectors.favourite.toggle, function() {
var toggleElement = $(this);
var forumId = toggleElement.data('forumid');
@ -73,10 +89,13 @@ define([
Repository.setDiscussionLockState(forumId, discussionId, state)
.then(function(context) {
var icon = toggleElement.parents(Selectors.summary.actions).find(Selectors.lock.icon);
var lockedLabel = toggleElement.parents(Selectors.discussion.item).find(Selectors.discussion.lockedLabel);
if (context.locked) {
icon.removeClass('hidden');
lockedLabel.removeAttr('hidden');
} else {
icon.addClass('hidden');
lockedLabel.attr('hidden', true);
}
return context;
})

View File

@ -0,0 +1,28 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Events for the forum activity.
*
* @module mod_forum/forum_events
* @package mod_forum
* @copyright 2019 Jun Pataleta <jun@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([], function() {
return {
SUBSCRIPTION_TOGGLED: 'mod_forum/subscription_toggle:subscriptionToggled',
};
});

View File

@ -65,7 +65,11 @@ define([], function() {
toggle: "[data-type='pin-toggle'][data-action='toggle']",
},
discussion: {
tools: '[data-container="discussion-tools"]'
}
tools: '[data-container="discussion-tools"]',
item: '[data-region="discussion-list-item"]',
lockedLabel: "[data-region='locked-label']",
subscribedLabel: "[data-region='subscribed-label']",
timedLabel: "[data-region='timed-label']",
},
};
});

View File

@ -28,12 +28,16 @@ define([
'core/notification',
'mod_forum/repository',
'mod_forum/selectors',
'core/pubsub',
'mod_forum/forum_events',
], function(
$,
Templates,
Notification,
Repository,
Selectors
Selectors,
PubSub,
ForumEvents
) {
/**
@ -50,6 +54,10 @@ define([
Repository.setDiscussionSubscriptionState(forumId, discussionId, subscriptionState)
.then(function(context) {
PubSub.publish(ForumEvents.SUBSCRIPTION_TOGGLED, {
discussionId: discussionId,
subscriptionState: subscriptionState
});
return Templates.render('mod_forum/discussion_subscription_toggle', context);
})
.then(function(html, js) {

View File

@ -180,7 +180,13 @@ class exported_discussion_summaries {
'isrepliesdesc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_DESC,
'isrepliesasc' => $sortorder == $discussionlistvault::SORTORDER_REPLIES_ASC,
'iscreateddesc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_DESC,
'iscreatedasc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_ASC
'iscreatedasc' => $sortorder == $discussionlistvault::SORTORDER_CREATED_ASC,
'isdiscussiondesc' => $sortorder == $discussionlistvault::SORTORDER_DISCUSSION_DESC,
'isdiscussionasc' => $sortorder == $discussionlistvault::SORTORDER_DISCUSSION_ASC,
'isstarterdesc' => $sortorder == $discussionlistvault::SORTORDER_STARTER_DESC,
'isstarterasc' => $sortorder == $discussionlistvault::SORTORDER_STARTER_ASC,
'isgroupdesc' => $sortorder == $discussionlistvault::SORTORDER_GROUP_DESC,
'isgroupasc' => $sortorder == $discussionlistvault::SORTORDER_GROUP_ASC,
);
$exportedposts['state']['sortorder'] = $sortoptions;

View File

@ -180,9 +180,11 @@ class discussion extends exporter {
if (!$group->hidepicture) {
$url = get_group_picture_url($group, $forum->get_course_id(), true);
if (!empty($url)) {
$groupdata['urls']['picture'] = $url;
if (empty($url)) {
// Get a generic group image URL.
$url = $output->image_url('g/g1')->out(false);
}
$groupdata['urls']['picture'] = $url;
}
if ($capabilitymanager->can_view_participants($user, $discussion)) {

View File

@ -89,6 +89,12 @@ class forum extends exporter {
'sortlastpostdesc' => ['type' => PARAM_URL],
'sortcreatedasc' => ['type' => PARAM_URL],
'sortcreateddesc' => ['type' => PARAM_URL],
'sortdiscussionasc' => ['type' => PARAM_URL],
'sortdiscussiondesc' => ['type' => PARAM_URL],
'sortstarterasc' => ['type' => PARAM_URL],
'sortstarterdesc' => ['type' => PARAM_URL],
'sortgroupasc' => ['type' => PARAM_URL],
'sortgroupdesc' => ['type' => PARAM_URL],
],
],
];
@ -137,7 +143,19 @@ class forum extends exporter {
'sortcreatedasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_CREATED_ASC)->out(false),
'sortcreateddesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_CREATED_DESC)->out(false)
$discussionvault::SORTORDER_CREATED_DESC)->out(false),
'sortdiscussionasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_DISCUSSION_ASC)->out(false),
'sortdiscussiondesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_DISCUSSION_DESC)->out(false),
'sortstarterasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_STARTER_ASC)->out(false),
'sortstarterdesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_STARTER_DESC)->out(false),
'sortgroupasc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_GROUP_ASC)->out(false),
'sortgroupdesc' => $urlfactory->get_forum_view_url_from_forum($this->forum, null,
$discussionvault::SORTORDER_GROUP_DESC)->out(false),
],
];
}

View File

@ -219,10 +219,6 @@ class discussion {
$capabilities = (array) $exporteddiscussion['capabilities'];
if ($capabilities['subscribe']) {
$exporteddiscussion['html']['subscribe'] = $this->get_subscription_button_html();
}
if ($capabilities['move']) {
$exporteddiscussion['html']['movediscussion'] = $this->get_move_discussion_html();
}
@ -295,26 +291,6 @@ class discussion {
return $this->renderer->render($select);
}
/**
* Get the HTML to render the subscription button.
*
* @return string
*/
private function get_subscription_button_html() : string {
global $PAGE;
$forumrecord = $this->forumrecord;
$discussion = $this->discussion;
$html = html_writer::div(
forum_get_discussion_subscription_icon($forumrecord, $discussion->get_id(), null, true),
'discussionsubscription'
);
$html .= forum_get_discussion_subscription_icon_preloaders();
// Add the subscription toggle JS.
$PAGE->requires->yui_module('moodle-mod_forum-subscriptiontoggle', 'Y.M.mod_forum.subscriptiontoggle.init');
return $html;
}
/**
* Get the HTML to render the move discussion selector and button.
*

View File

@ -26,6 +26,7 @@ namespace mod_forum\local\vaults;
defined('MOODLE_INTERNAL') || die();
use core_group\output\group_details;
use mod_forum\local\vaults\preprocessors\extract_record as extract_record_preprocessor;
use mod_forum\local\vaults\preprocessors\extract_user as extract_user_preprocessor;
use mod_forum\local\renderers\discussion_list as discussion_list_renderer;
@ -70,6 +71,18 @@ class discussion_list extends db_table_vault {
public const SORTORDER_REPLIES_DESC = 5;
/** Sort by number of replies desc */
public const SORTORDER_REPLIES_ASC = 6;
/** Sort by discussion name desc */
public const SORTORDER_DISCUSSION_DESC = 7;
/** Sort by discussion name asc */
public const SORTORDER_DISCUSSION_ASC = 8;
/** Sort by discussion starter's name desc */
public const SORTORDER_STARTER_DESC = 9;
/** Sort by discussion starter's name asc */
public const SORTORDER_STARTER_ASC = 10;
/** Sort by group name desc */
public const SORTORDER_GROUP_DESC = 11;
/** Sort by group name asc */
public const SORTORDER_GROUP_ASC = 12;
/**
* Get the table alias.
@ -94,14 +107,12 @@ class discussion_list extends db_table_vault {
*
* @param string|null $wheresql Where conditions for the SQL
* @param string|null $sortsql Order by conditions for the SQL
* @param string|null $joinsql Additional join conditions for the sql
* @param int|null $userid The ID of the user we are performing this query for
* @param int|null $userid The ID of the user we are performing this query for
*
* @return string
*/
protected function generate_get_records_sql(string $wheresql = null, ?string $sortsql = null, ?int $userid = null) : string {
$alias = $this->get_table_alias();
$db = $this->get_db();
$includefavourites = $userid ? true : false;
@ -153,6 +164,18 @@ class discussion_list extends db_table_vault {
) r ON d.id = r.id';
}
$groupsortorders = [
$this->get_sort_order(self::SORTORDER_GROUP_DESC, $includefavourites),
$this->get_sort_order(self::SORTORDER_GROUP_ASC, $includefavourites)
];
$sortbygroup = in_array($sortsql, $groupsortorders);
if ($sortbygroup) {
$groupstable = new dml_table('groups', 'g', 'g');
$fields .= ', ' . $groupstable->get_field_select();
// Join groups.
$tables .= 'LEFT JOIN {groups} g ON g.id = d.groupid';
}
$selectsql = 'SELECT ' . $fields . ' FROM ' . $tables;
$selectsql .= $wheresql ? ' WHERE ' . $wheresql : '';
$selectsql .= $sortsql ? ' ORDER BY ' . $sortsql : '';
@ -226,6 +249,8 @@ class discussion_list extends db_table_vault {
* @return string
*/
protected function get_keyfield(?int $sortmethod) : string {
global $CFG;
switch ($sortmethod) {
case self::SORTORDER_CREATED_DESC:
case self::SORTORDER_CREATED_ASC:
@ -233,6 +258,30 @@ class discussion_list extends db_table_vault {
case self::SORTORDER_REPLIES_DESC:
case self::SORTORDER_REPLIES_ASC:
return 'replycount';
case self::SORTORDER_DISCUSSION_DESC:
case self::SORTORDER_DISCUSSION_ASC:
return 'dname';
case self::SORTORDER_STARTER_DESC:
case self::SORTORDER_STARTER_ASC:
// We'll sort by the first name field of the discussion starter's name.
// Let's get the full name display config first.
$nameformat = $CFG->fullnamedisplay;
if ($CFG->fullnamedisplay === 'language') {
$nameformat = get_string('fullnamedisplay', '', (object)['firstname' => 'firstname', 'lastname' => 'lastname']);
}
// Fetch all the available user name fields.
$availablefields = order_in_string(get_all_user_name_fields(), $nameformat);
// We'll default to the first name if there's no available name field.
$returnfield = 'firstname';
if (!empty($availablefields)) {
// Use the first name field.
$returnfield = reset($availablefields);
}
return 'fauserrecord' . $returnfield;
case self::SORTORDER_GROUP_DESC:
case self::SORTORDER_GROUP_ASC:
return 'gname';
default:
global $CFG;
$alias = $this->get_table_alias();
@ -255,11 +304,16 @@ class discussion_list extends db_table_vault {
case self::SORTORDER_LASTPOST_ASC:
case self::SORTORDER_CREATED_ASC:
case self::SORTORDER_REPLIES_ASC:
case self::SORTORDER_DISCUSSION_ASC:
case self::SORTORDER_STARTER_ASC:
case self::SORTORDER_GROUP_ASC:
return "ASC";
case self::SORTORDER_LASTPOST_DESC:
case self::SORTORDER_CREATED_DESC:
case self::SORTORDER_REPLIES_DESC:
return "DESC";
case self::SORTORDER_DISCUSSION_DESC:
case self::SORTORDER_STARTER_DESC:
case self::SORTORDER_GROUP_DESC:
default:
return "DESC";
}

View File

@ -166,10 +166,16 @@ $string['disallowsubscribeteacher'] = 'Subscriptions not allowed (except for tea
$string['discussion'] = 'Discussion';
$string['discussionlistsortbycreatedasc'] = 'Sort by creation date in ascending order';
$string['discussionlistsortbycreateddesc'] = 'Sort by creation date in descending order';
$string['discussionlistsortbydiscussionasc'] = 'Sort by discussion name in ascending order';
$string['discussionlistsortbydiscussiondesc'] = 'Sort by discussion name in descending order';
$string['discussionlistsortbygroupasc'] = 'Sort by group in ascending order';
$string['discussionlistsortbygroupdesc'] = 'Sort by group in descending order';
$string['discussionlistsortbylastpostdesc'] = 'Sort by last post creation date in descending order';
$string['discussionlistsortbylastpostasc'] = 'Sort by last post creation date in ascending order';
$string['discussionlistsortbyrepliesasc'] = 'Sort by number of replies in ascending order';
$string['discussionlistsortbyrepliesdesc'] = 'Sort by number of replies in descending order';
$string['discussionlistsortbystarterasc'] = 'Sort by discussion starter name in ascending order';
$string['discussionlistsortbystarterdesc'] = 'Sort by discussion starter name in descending order';
$string['discussionlocked'] = 'This discussion has been locked so you can no longer reply to it.';
$string['discussionlockingheader'] = 'Discussion locking';
$string['discussionlockingdisabled'] = 'Do not lock discussions';
@ -182,6 +188,7 @@ $string['discussionpin'] = 'Pin';
$string['discussionpinned'] = 'Pinned';
$string['discussionpinned_help'] = 'Pinned discussions will appear at the top of a forum.';
$string['discussionsplit'] = 'Discussion has been split';
$string['discussionsubscribed'] = 'You are now subscribed to this discussion.';
$string['discussionsubscribestop'] = 'I don\'t want to be notified of new posts in this discussion';
$string['discussionsubscribestart'] = 'Send me notifications of new posts in this discussion';
$string['discussionsubscription'] = 'Discussion subscription';
@ -191,13 +198,16 @@ $string['discussionsstartedby'] = 'Discussions started by {$a}';
$string['discussionsstartedbyrecent'] = 'Discussions recently started by {$a}';
$string['discussionsstartedbyuserincourse'] = 'Discussions started by {$a->fullname} in {$a->coursename}';
$string['discussionunpin'] = 'Unpin';
$string['discussionunsubscribed'] = 'You are now unsubscribed from this discussion.';
$string['discussthistopic'] = 'Discuss this topic';
$string['displayend'] = 'Display end';
$string['displayend_help'] = 'This setting specifies whether a forum post should be hidden after a certain date. Note that administrators can always view forum posts.';
$string['displayenddate'] = 'Display end: {$a}.';
$string['displaymode'] = 'Display mode';
$string['displayperiod'] = 'Display period';
$string['displaystart'] = 'Display start';
$string['displaystart_help'] = 'This setting specifies whether a forum post should be displayed from a certain date. Note that administrators can always view forum posts.';
$string['displaystartdate'] = 'Display start: {$a}.';
$string['displaywordcount'] = 'Display word count';
$string['displaywordcount_help'] = 'This setting specifies whether the word count of each post should be displayed or not.';
$string['duedate'] = 'Due date';
@ -350,6 +360,7 @@ $string['mailnow'] = 'Send forum post notifications with no editing-time delay';
$string['manydiscussions'] = 'Discussions per page';
$string['managesubscriptionsoff'] = 'Finish managing subscriptions';
$string['managesubscriptionson'] = 'Manage subscribers';
$string['markasread'] = 'Mark as read';
$string['markalldread'] = 'Mark all posts in this discussion read.';
$string['markallread'] = 'Mark all posts in this forum read.';
$string['markasreadonnotification'] = 'When sending forum post notifications';
@ -642,6 +653,8 @@ $string['tagsdeleted'] = 'Forum tags have been deleted';
$string['thisforumisthrottled'] = 'This forum has a limit to the number of forum postings you can make in a given time period - this is currently set at {$a->blockafter} posting(s) in {$a->blockperiod}';
$string['thisforumisdue'] = 'The due date for posting to this forum was {$a}.';
$string['thisforumhasduedate'] = 'The due date for posting to this forum is {$a}.';
$string['timed'] = 'Timed';
$string['timeddiscussion'] = 'Timed discussion';
$string['timedhidden'] = 'Timed status: Hidden from students';
$string['timedposts'] = 'Timed posts';
$string['timedvisible'] = 'Timed status: Visible to all users';

View File

@ -2426,7 +2426,7 @@ function forum_get_discussion_subscription_icon($forum, $discussionid, $returnur
return html_writer::link($subscriptionlink, $output, array(
'title' => get_string('clicktounsubscribe', 'forum'),
'class' => 'discussiontoggle iconsmall',
'class' => 'discussiontoggle btn btn-link',
'data-forumid' => $forum->id,
'data-discussionid' => $discussionid,
'data-includetext' => $includetext,
@ -2440,7 +2440,7 @@ function forum_get_discussion_subscription_icon($forum, $discussionid, $returnur
return html_writer::link($subscriptionlink, $output, array(
'title' => get_string('clicktosubscribe', 'forum'),
'class' => 'discussiontoggle iconsmall',
'class' => 'discussiontoggle btn btn-link',
'data-forumid' => $forum->id,
'data-discussionid' => $discussionid,
'data-includetext' => $includetext,

View File

@ -1,70 +0,0 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Subscribe to or unsubscribe from a forum discussion.
*
* @package mod_forum
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define('AJAX_SCRIPT', true);
require(__DIR__.'/../../config.php');
require_once($CFG->dirroot . '/mod/forum/lib.php');
$forumid = required_param('forumid', PARAM_INT); // The forum to subscribe or unsubscribe.
$discussionid = optional_param('discussionid', null, PARAM_INT); // The discussionid to subscribe.
$includetext = optional_param('includetext', false, PARAM_BOOL);
$forum = $DB->get_record('forum', array('id' => $forumid), '*', MUST_EXIST);
$course = $DB->get_record('course', array('id' => $forum->course), '*', MUST_EXIST);
if (!$discussion = $DB->get_record('forum_discussions', array('id' => $discussionid, 'forum' => $forumid))) {
print_error('invaliddiscussionid', 'forum');
}
$cm = get_coursemodule_from_instance('forum', $forum->id, $course->id, false, MUST_EXIST);
$context = context_module::instance($cm->id);
require_sesskey();
require_login($course, false, $cm);
require_capability('mod/forum:viewdiscussion', $context);
$return = new stdClass();
if (is_guest($context, $USER)) {
// is_guest should be used here as this also checks whether the user is a guest in the current course.
// Guests and visitors cannot subscribe - only enrolled users.
throw new moodle_exception('noguestsubscribe', 'mod_forum');
}
if (!\mod_forum\subscriptions::is_subscribable($forum)) {
// Nothing to do. We won't actually output any content here though.
echo json_encode($return);
die;
}
if (\mod_forum\subscriptions::is_subscribed($USER->id, $forum, $discussion->id, $cm)) {
// The user is subscribed, unsubscribe them.
\mod_forum\subscriptions::unsubscribe_user_from_discussion($USER->id, $discussion, $context);
} else {
// The user is unsubscribed, subscribe them.
\mod_forum\subscriptions::subscribe_user_to_discussion($USER->id, $discussion, $context);
}
// Now return the updated subscription icon.
$return->icon = forum_get_discussion_subscription_icon($forum, $discussion->id, null, $includetext);
echo json_encode($return);
die;

View File

@ -73,41 +73,57 @@
{{#str}} showingcountoftotaldiscussions, mod_forum, {"count": "{{visiblediscussioncount}}", "total":"{{totaldiscussioncount}}"} {{/str}}
</span>
<table
class="table table-hover table-striped discussion-list"
class="table table-hover discussion-list"
aria-label='{{#str}} showingcountoftotaldiscussions, mod_forum, {"count": "{{visiblediscussioncount}}", "total":"{{totaldiscussioncount}}"} {{/str}}'
aria-describedby="discussion-table-description-{{uniqid}}"
>
{{$discussion_list_header}}
<thead>
<tr>
<th scope="col">&nbsp;</th>
<th scope="col" class="p-l-0">{{#str}}discussion, mod_forum{{/str}}</th>
<th scope="col" class="author">{{#str}}startedby, mod_forum{{/str}}</th>
<th scope="col">
<span class="accesshide">{{#str}}status{{/str}}</span>
</th>
<th scope="col" class="p-l-0">
{{#state.sortorder.isdiscussiondesc}}
<a href="{{{forum.urls.sortdiscussionasc}}}" aria-label="{{#str}}discussionlistsortbydiscussionasc, mod_forum{{/str}}">{{#str}}discussion, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isdiscussiondesc}}
{{#state.sortorder.isdiscussionasc}}
<a href="{{{forum.urls.sortdiscussiondesc}}}" aria-label="{{#str}}discussionlistsortbydiscussiondesc, mod_forum{{/str}}">{{#str}}discussion, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isdiscussionasc}}
{{^state.sortorder.isdiscussiondesc}}
{{^state.sortorder.isdiscussionasc}}
<a href="{{{forum.urls.sortdiscussiondesc}}}" aria-label="{{#str}}discussionlistsortbydiscussiondesc, mod_forum{{/str}}">{{#str}}discussion, mod_forum{{/str}}</a>
{{/state.sortorder.isdiscussionasc}}
{{/state.sortorder.isdiscussiondesc}}
</th>
{{#forum.state.groupmode}}
<th scope="col" class="group">{{#str}}group{{/str}}</th>
<th scope="col" class="group">
{{#state.sortorder.isgroupdesc}}
<a href="{{{forum.urls.sortgroupasc}}}" aria-label="{{#str}}discussionlistsortbygroupasc, mod_forum{{/str}}">{{#str}}group{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isgroupdesc}}
{{#state.sortorder.isgroupasc}}
<a href="{{{forum.urls.sortgroupdesc}}}" aria-label="{{#str}}discussionlistsortbygroupdesc, mod_forum{{/str}}">{{#str}}group{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isgroupasc}}
{{^state.sortorder.isgroupdesc}}
{{^state.sortorder.isgroupasc}}
<a href="{{{forum.urls.sortgroupdesc}}}" aria-label="{{#str}}discussionlistsortbygroupdesc, mod_forum{{/str}}">{{#str}}group{{/str}}</a>
{{/state.sortorder.isgroupasc}}
{{/state.sortorder.isgroupdesc}}
</th>
{{/forum.state.groupmode}}
{{#forum.capabilities.viewdiscussions}}
<th scope="col" class="text-center">
{{#state.sortorder.isrepliesdesc}}
<a href="{{{forum.urls.sortrepliesasc}}}" aria-label="{{#str}}discussionlistsortbyrepliesasc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isrepliesdesc}}
{{#state.sortorder.isrepliesasc}}
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isrepliesasc}}
{{^state.sortorder.isrepliesdesc}}
{{^state.sortorder.isrepliesasc}}
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a>
{{/state.sortorder.isrepliesasc}}
{{/state.sortorder.isrepliesdesc}}
</th>
{{#forum.userstate.tracked}}
<th scope="col" class="text-center">
{{#str}}unread, mod_forum{{/str}}
<a href="{{{forum.urls.markasread}}}">{{#pix}}t/markasread, core, {{#str}}markallread, mod_forum{{/str}}{{/pix}}</a>
</th>
{{/forum.userstate.tracked}}
{{/forum.capabilities.viewdiscussions}}
<th scope="col" class="author">
{{#state.sortorder.isstarterdesc}}
<a href="{{{forum.urls.sortstarterasc}}}" aria-label="{{#str}}discussionlistsortbystarterasc, mod_forum{{/str}}">{{#str}}startedby, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isstarterdesc}}
{{#state.sortorder.isstarterasc}}
<a href="{{{forum.urls.sortstarterdesc}}}" aria-label="{{#str}}discussionlistsortbystarterdesc, mod_forum{{/str}}">{{#str}}startedby, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isstarterasc}}
{{^state.sortorder.isstarterdesc}}
{{^state.sortorder.isstarterasc}}
<a href="{{{forum.urls.sortstarterdesc}}}" aria-label="{{#str}}discussionlistsortbystarterdesc, mod_forum{{/str}}">{{#str}}startedby, mod_forum{{/str}}</a>
{{/state.sortorder.isstarterasc}}
{{/state.sortorder.isstarterdesc}}
</th>
<th scope="col" class="lastpost">
{{#state.sortorder.islastpostdesc}}
<a href="{{{forum.urls.sortlastpostasc}}}" aria-label="{{#str}}discussionlistsortbylastpostasc, mod_forum{{/str}}">{{#str}}lastpost, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
@ -121,21 +137,27 @@
{{/state.sortorder.islastpostasc}}
{{/state.sortorder.islastpostdesc}}
</th>
<th scope="col" class="created">
{{#state.sortorder.iscreateddesc}}
<a href="{{{forum.urls.sortcreatedasc}}}" aria-label="{{#str}}discussionlistsortbycreatedasc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.iscreateddesc}}
{{#state.sortorder.iscreatedasc}}
<a href="{{{forum.urls.sortcreateddesc}}}" aria-label="{{#str}}discussionlistsortbycreateddesc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.iscreatedasc}}
{{^state.sortorder.iscreateddesc}}
{{^state.sortorder.iscreatedasc}}
<a href="{{{forum.urls.sortcreateddesc}}}" aria-label="{{#str}}discussionlistsortbycreateddesc, mod_forum{{/str}}">{{#str}}created, mod_forum{{/str}}</a>
{{/state.sortorder.iscreatedasc}}
{{/state.sortorder.iscreateddesc}}
{{#forum.capabilities.viewdiscussions}}
<th scope="col" class="text-center">
{{#state.sortorder.isrepliesdesc}}
<a href="{{{forum.urls.sortrepliesasc}}}" aria-label="{{#str}}discussionlistsortbyrepliesasc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/downlong, core, {{#str}}desc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isrepliesdesc}}
{{#state.sortorder.isrepliesasc}}
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a> <span class="text-primary">{{#pix}}t/uplong, core, {{#str}}asc, core{{/str}}{{/pix}}</span>
{{/state.sortorder.isrepliesasc}}
{{^state.sortorder.isrepliesdesc}}
{{^state.sortorder.isrepliesasc}}
<a href="{{{forum.urls.sortrepliesdesc}}}" aria-label="{{#str}}discussionlistsortbyrepliesdesc, mod_forum{{/str}}">{{#str}}replies, mod_forum{{/str}}</a>
{{/state.sortorder.isrepliesasc}}
{{/state.sortorder.isrepliesdesc}}
{{#forum.userstate.tracked}}
<a href="{{{forum.urls.markasread}}}">{{#pix}}t/markasread, core, {{#str}}markallread, mod_forum{{/str}}{{/pix}}</a>
{{/forum.userstate.tracked}}
</th>
{{/forum.capabilities.viewdiscussions}}
<th scope="col" class="discussionsubscription">
<span class="accesshide">{{#str}}actions{{/str}}</span>
</th>
<th scope="col">&nbsp;</th>
<th scope="col" class="discussionsubscription"></th>
</tr>
</thead>
{{/discussion_list_header}}
@ -143,8 +165,11 @@
<tbody>
{{#summaries}}
<!-- The discussion class is only required for behat tests to identify the row -->
<tr class="discussion {{#discussion.timed}}{{#istimed}}{{^visible}}dimmed_text{{/visible}}{{/istimed}}{{/discussion.timed}}">
<td scope="col" class="pinned p-0 text-center align-middle">
<tr class="discussion {{#discussion.timed}}{{#istimed}}{{^visible}}dimmed_text{{/visible}}{{/istimed}}{{/discussion.timed}}"
data-region="discussion-list-item"
data-discussionid="{{id}}"
data-forumid="{{forumid}}">
<td class="pinned p-0 text-center align-middle icon-no-margin" style="width: 1px;">
{{#discussion.pinned}}
{{#pix}}i/pinned, mod_forum, {{#str}}discussionpinned, mod_forum{{/str}}{{/pix}}
{{/discussion.pinned}}
@ -154,146 +179,100 @@
{{/discussion}}
{{/discussion.pinned}}
</td>
<td scope="col" class="topic p-0 align-middle">
<a class="p-3 p-l-0 w-100 h-100 d-block" href="{{discussion.urls.view}}">{{{discussion.name}}}</a>
</td>
<td scope="col" class="author align-middle">
<th scope="row" class="topic p-0 align-middle">
<div class="p-3 p-l-0">
<a class="w-100 h-100 d-block" href="{{discussion.urls.view}}" title="{{discussion.name}}" aria-label="{{discussion.name}}">
{{#shortentext}}100, {{{discussion.name}}}{{/shortentext}}
</a>
<div>
<span class="badge badge-danger rounded" data-region="locked-label" {{^discussion.locked}}hidden{{/discussion.locked}}>
{{#str}}locked, forum{{/str}}
</span>
<span class="badge badge-light rounded" data-region="subscribed-label" {{^discussion.userstate.subscribed}}hidden{{/discussion.userstate.subscribed}}>
{{#str}}subscribed, forum{{/str}}
</span>
{{#discussion.timed.istimed}}
<span>
<button class="btn badge badge-primary rounded border-0" data-region="timed-label"
data-toggle="popover" data-container="body" data-placement="right" data-html="true"
data-content='{{#discussion.timed}}{{#discussion.times}}{{> mod_forum/discussion_times}}{{/discussion.times}}{{/discussion.timed}}'
data-trigger="click" aria-label="{{#str}}timeddiscussion, forum{{/str}}" title="{{#str}}timeddiscussion, forum{{/str}}">
{{#str}}timed, forum{{/str}}
</button>
</span>
{{/discussion.timed.istimed}}
</div>
</div>
</th>
{{#forum.state.groupmode}}
<td class="group align-middle">
{{#discussion.group}}
<img alt="{{#str}} pictureof, core, {{name}} {{/str}}"
class="border rounded h-auto rounded-circle grouppicture"
src="{{{urls.picture}}}"
title="{{#str}} pictureof, core, {{name}} {{/str}}">
{{#urls.userlist}}
<a href="{{{urls.userlist}}}" aria-label='{{#str}} memberofgroup, group, {{name}}{{/str}}'
title='{{#str}} memberofgroup, group, {{name}}{{/str}}'>
{{#shortentext}}30, {{name}}{{/shortentext}}
</a>
{{/urls.userlist}}
{{^urls.userlist}}
<span>{{name}}</span>
{{/urls.userlist}}
{{/discussion.group}}
</td>
{{/forum.state.groupmode}}
<td class="author align-middle">
{{#firstpostauthor}}
<div class="d-flex flex-row">
<div class="align-middle p-0">
<img
class="rounded-circle userpicture"
src="{{urls.profileimage}}"
alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
>
<img class="rounded-circle userpicture" src="{{urls.profileimage}}"
alt="{{#str}}pictureof, moodle, {{fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{fullname}}{{/str}}" >
</div>
<div class="align-middle p-2">
{{fullname}}
<div class="align-middle">
<div>{{fullname}}</div>
<div>
<small>{{#userdate}}{{discussion.times.created}}, {{#str}}strftimedatemonthabbr, langconfig{{/str}}{{/userdate}}</small>
</div>
</div>
</div>
{{/firstpostauthor}}
</td>
{{#forum.state.groupmode}}
<td scope="col" class="group align-middle">
{{#discussion.group}}
{{#urls.picture}}
{{#urls.userlist}}
<a href="{{{urls.userlist}}}" role="button" aria-label='{{#str}} memberofgroup, group, {{name}}{{/str}}'>
<img alt="{{#str}} pictureof, core, {{name}} {{/str}}"
aria-hidden="true"
class="border rounded h-auto rounded-circle grouppicture"
src="{{{urls.picture}}}"
title="{{#str}} pictureof, core, {{name}} {{/str}}">
</a>
{{/urls.userlist}}
{{^urls.userlist}}
<img alt="{{#str}} pictureof, core, {{name}} {{/str}}"
class="border rounded h-auto rounded-circle grouppicture"
src="{{{urls.picture}}}"
title="{{#str}} pictureof, core, {{name}} {{/str}}">
{{/urls.userlist}}
{{/urls.picture}}
{{^urls.picture}}
{{#urls.userlist}}
<a href="{{{urls.userlist}}}" aria-label='{{#str}} memberofgroup, group, {{name}}{{/str}}'>{{name}}</a>
{{/urls.userlist}}
{{^urls.userlist}}
{{name}}
{{/urls.userlist}}
{{/urls.picture}}
{{/discussion.group}}
</td>
{{/forum.state.groupmode}}
{{#forum.capabilities.viewdiscussions}}
<td scope="col" class="p-0 text-center align-middle">
<a href="{{discussion.urls.view}}" class="p-3 w-100 h-100 d-block">
{{replies}}
</a>
</td>
{{#forum.userstate.tracked}}
<td scope="col" class="p-0 text-center align-middle">
{{#unread}}
{{! TODO Rewrite as AJAX}}
<span class="p-1 w-100 h-100 d-block unread">
<a href="{{{discussion.urls.viewfirstunread}}}">{{unread}}</a>
<a href="{{{discussion.urls.markasread}}}">{{#pix}}t/markasread, core, {{#str}}markalldread, mod_forum{{/str}}{{/pix}}</a>
</span>
{{/unread}}
{{^unread}}
<span class="p-3 w-100 h-100 d-block">
0
</span>
{{/unread}}
</td>
{{/forum.userstate.tracked}}
{{/forum.capabilities.viewdiscussions}}
<td scope="col" class="text-left align-middle">
<td class="text-left align-middle">
{{! TODO Check q&a, eachuser }}
{{#latestpostid}}
<div class="d-flex flex-row">
<div class="align-middle p-0">
<a href="{{latestpostauthor.urls.profile}}">
<img
class="rounded-circle userpicture"
src="{{latestpostauthor.urls.profileimage}}"
alt="{{#str}}pictureof, moodle, {{latestpostauthor.fullname}}{{/str}}"
title="{{#str}}pictureof, moodle, {{latestpostauthor.fullname}}{{/str}}"
>
</a>
</div>
<div class="p-2 p-t-0 p-b-0 d-inline-flex flex-column">
<div>
<a href="{{latestpostauthor.urls.profile}}">{{latestpostauthor.fullname}}</a>
</div>
<div>
<a href="{{{discussion.urls.viewlatest}}}">{{#userdate}}
{{discussion.times.modified}}, {{#str}}strftimerecentfull{{/str}}
{{/userdate}}</a>
</div>
</div>
</div>
<a href="{{{discussion.urls.viewlatest}}}" title="{{#userdate}}{{discussion.times.modified}},{{#str}}strftimerecentfull{{/str}}{{/userdate}}">
{{#userdate}}
{{discussion.times.modified}}, {{#str}}strftimedateshortmonthabbr, langconfig{{/str}}
{{/userdate}}
</a>
{{/latestpostid}}
</td>
<td scope="col" class="text-left align-middle">
{{#userdate}}{{discussion.times.created}}, {{#str}}strftimerecentfull{{/str}}{{/userdate}}
</td>
<td scope="col" class="timed p-0 text-center align-middle">
{{#discussion.timed.istimed}}
<div class="timedpost">
{{#pix}}
i/calendar, moodle,
{{#discussion.times.start}}
{{! }}{{#str}} displaystart, mod_forum {{/str}}: {{#userdate}}{{.}}, {{#str}}strftimerecentfull {{/str}}{{/userdate}}
{{/discussion.times.start}}
{{#discussion.times.end}}
{{! }}{{#str}} displayend, mod_forum {{/str}}: {{#userdate}}{{.}}, {{#str}} strftimerecentfull {{/str}}{{/userdate}}
{{/discussion.times.end}}
{{#discussion.timed.visible}}
{{! }}{{#str}} timedvisible, mod_forum {{/str}}
{{/discussion.timed.visible}}
{{^discussion.timed.visible}}
{{! }}{{#str}} timedhidden, mod_forum {{/str}}
{{/discussion.timed.visible}}
{{/pix}}
</div>
{{/discussion.timed.istimed}}
</td>
<td scope="col" class="p-0 align-middle" data-container="discussion-summary-actions">
{{#forum.capabilities.viewdiscussions}}
<td class="p-0 text-center align-middle">
<span>{{replies}}</span>
{{#forum.userstate.tracked}}
{{#unread}}
{{! TODO Rewrite as AJAX}}
<span class="lead">
<a href="{{{discussion.urls.viewfirstunread}}}" class="badge badge-primary rounded-pill font-weight-normal"
title="{{#str}}unreadpostsnumber, mod_forum, {{unread}}{{/str}}" aria-label="{{#str}}unreadpostsnumber, mod_forum, {{unread}}{{/str}}">
{{unread}}
</a>
</span>
{{/unread}}
{{/forum.userstate.tracked}}
</td>
{{/forum.capabilities.viewdiscussions}}
<td class="p-0 align-middle" data-container="discussion-summary-actions" style="width: 1px;">
{{#discussion}}
<div class="d-flex flex-wrap justify-content-end pr-4">
<div class="pt-1 mt-2 {{^discussion.locked}}hidden{{/discussion.locked}}" data-region="locked-icon">
<span class="btn" >{{#pix}}i/lock, core, {{#str}}locked, forum{{/str}}{{/pix}}</span>
</div>
{{#forum.capabilities.subscribe}}
<div>
{{> mod_forum/discussion_subscription_toggle}}
</div>
{{/forum.capabilities.subscribe}}
<div class="d-flex flex-wrap justify-content-end icon-no-margin">
{{#hasanyactions}}
<div class="mt-3" data-container='discussion-tools'>
{{> mod_forum/forum_action_menu}}
</div>
<div data-container='discussion-tools'>
{{> mod_forum/forum_action_menu}}
</div>
{{/hasanyactions}}
</div>
{{/discussion}}

View File

@ -26,16 +26,26 @@
* none
Context variables required for this template:
* TODO
* capabilities Object - Uses the "subscribe" attribute to determine whether to render the subscribe action.
* urls Object - Uses the "subscribe" attribute for the subscription URl.
* id int - The discussion ID.
* forumid int - The forum ID.
* userstate Object - Uses the "subscribed" attribute to determine the action that will be performed upon toggling.
Example context (json):
{
"capabilities": { "subscribe": true },
"urls": { "subscribe": "#" },
"id": 1,
"forumid": 1,
"userstate": { "subscribed": true }
}
}}
{{#capabilities.subscribe}}
<a
href="{{{urls.subscribe}}}"
class="py-3 btn btn-link"
class="dropdown-item"
role="menuitem"
data-type="subscription-toggle"
data-action="toggle"
data-discussionid="{{id}}"
@ -50,10 +60,10 @@
{{/userstate.subscribed}}
>
{{#userstate.subscribed}}
{{#pix}}t/subscribed, mod_forum, {{#str}}clicktounsubscribe, mod_forum{{/str}}{{/pix}}
{{#str}}unsubscribediscussion, forum{{/str}}
{{/userstate.subscribed}}
{{^userstate.subscribed}}
{{#pix}}t/unsubscribed, mod_forum, {{#str}}clicktosubscribe, mod_forum{{/str}}{{/pix}}
{{#str}}subscribediscussion, forum{{/str}}
{{/userstate.subscribed}}
</a>
{{/capabilities.subscribe}}

View File

@ -0,0 +1,59 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_forum/discussion_times
Template to display the discussion times.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* start int - The discussion start timestamp
* end int - The discussion end timestamp
* visible boolean - Whether the discussion is visible to students or not.
Example context (json):
{
"start": 1,
"end": 1,
"visible": true
}
}}
<ul>
{{#start}}
<li>
{{#str}} displaystartdate, mod_forum, {{#userdate}}{{.}}, {{#str}}strftimerecentfull {{/str}}{{/userdate}} {{/str}}
</li>
{{/start}}
{{#end}}
<li>
{{#str}} displayenddate, mod_forum, {{#userdate}}{{.}}, {{#str}}strftimerecentfull {{/str}}{{/userdate}} {{/str}}
</li>
{{/end}}
<li>
{{#visible}}
{{#str}} timedvisible, mod_forum {{/str}}
{{/visible}}
{{^visible}}
{{#str}} timedhidden, mod_forum {{/str}}
{{/visible}}
</li>
</ul>

View File

@ -15,18 +15,42 @@
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_forum/forum-action-menu
@template mod_forum/forum_action_menu
This template renders action menu for each course.
This template renders action menu for a forum discussion.
Context variables required for this template:
* capabilities Object - Uses the following attributes:
* manage boolean - Whether to render the lock action.
* favourite boolean - Whether to render the star/unstar action.
* pin boolean - Whether to render the star/unstar action.
* subscribe boolean - Whether to render the subscribe action.
* id int - The discussion ID.
* forumid int - The forum ID.
* istimelocked boolean - Whether this forum is time locked.
* settings Object - Uses the following attributes:
* excludetext boolean - Whether to show an icon only.
* togglemoreicon - Whether to show a toggle-more icon or not.
Example context (json):
{
"capabilities": {
"manage": true,
"favourite": true,
"pin": true,
"subscribe": true
},
"id": 1,
"forumid": 1,
"istimelocked": false,
"settings": {
"excludetext": false,
"togglemoreicon": false
}
}
}}
<div class="ml-auto dropdown">
<button class="{{^settings.excludetext}}dropdown-toggle{{/settings.excludetext}} m-t-0 p-t-0 btn btn-link"
type="button"
<a href="#" class="{{^settings.excludetext}}dropdown-toggle{{/settings.excludetext}} btn btn-link"
role="button"
data-toggle="dropdown"
aria-haspopup="true"
@ -34,7 +58,7 @@
aria-controls="forum-action-menu-{{id}}-menu"
aria-expanded="false">
{{#settings.togglemoreicon}}
{{#pix}} i/moremenu, core{{/pix}}
{{#pix}} i/menu, core{{/pix}}
{{/settings.togglemoreicon}}
{{^settings.togglemoreicon}}
{{#pix}} i/settings, core{{/pix}}
@ -42,9 +66,8 @@
{{^settings.excludetext}}
{{#str}} settings, mod_forum {{/str}}
{{/settings.excludetext}}
</button>
<div class="dropdown-menu dropdown-menu-right menu"
</a>
<div class="dropdown-menu dropdown-menu-right"
aria-labelledby="forum-action-menu-{{id}}-menu"
data-rel="menu-content"
role="menu"
@ -56,9 +79,13 @@
{{> mod_forum/discussion_pin_toggle}}
{{/capabilities.pin}}
{{#capabilities.manage}}
{{^istimelocked}}
{{> forum/discussion_lock_toggle }}
{{/istimelocked}}
{{^istimelocked}}
{{> forum/discussion_lock_toggle }}
{{/istimelocked}}
{{/capabilities.manage}}
{{> forum/discussion_subscription_toggle }}
{{#unread}}
{{> forum/mark_as_read }}
{{/unread}}
</div>
</div>
</div>

View File

@ -34,13 +34,11 @@
{{#html}}
{{#hasanyactions}}
<div class="d-flex flex-wrap flex-row-reverse m-b-1 text-right" data-container="discussion-tools">
<div class="pl-1">
<div class="discussion-settings-menu">
{{> mod_forum/forum_action_menu}}
</div>
</div>
<div class="pl-1">{{{subscribe}}}</div>
</div>
{{/hasanyactions}}
{{{neighbourlinks}}}
@ -61,8 +59,9 @@
{{#html.neighbourlinks}}{{{.}}}{{/html.neighbourlinks}}
</div>
{{#js}}
require(['jquery', 'mod_forum/discussion', 'mod_forum/posts_list', 'mod_forum/lock_toggle', 'mod_forum/favourite_toggle', 'mod_forum/pin_toggle'],
function($, Discussion, PostsList, LockToggle, FavouriteToggle, Pin) {
require(['jquery', 'mod_forum/discussion', 'mod_forum/posts_list', 'mod_forum/lock_toggle', 'mod_forum/favourite_toggle',
'mod_forum/pin_toggle', 'mod_forum/subscription_toggle'],
function($, Discussion, PostsList, LockToggle, FavouriteToggle, Pin, SubscribeToggle) {
var root = $("[data-content='forum-discussion']");
Discussion.init(root);
PostsList.init(root);
@ -70,5 +69,6 @@ require(['jquery', 'mod_forum/discussion', 'mod_forum/posts_list', 'mod_forum/lo
LockToggle.init(root);
FavouriteToggle.init(root);
Pin.init(root);
SubscribeToggle.init(root);
});
{{/js}}

View File

@ -0,0 +1,40 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template mod_forum/mark_as_read
Template to mark as read menu item.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* urls Object - Uses the 'markasread' attribute for the URL.
Example context (json):
{
"urls": {
"markasread": "#"
}
}
}}
<a class="dropdown-item menu-action" role="menuitem" href="{{{urls.markasread}}}">
<span class="menu-action-text">{{#str}}markasread, mod_forum{{/str}}</span>
</a>

View File

@ -25,18 +25,18 @@ Feature: Forum discussions can be split
| Forum type | Standard forum for general use |
| Description | Forum to discuss your coursework. |
And I add a new discussion to "Study discussions" forum with:
| Subject | Photosynethis discussion |
| Message | Lets discuss our learning about Photosynethis this week in this thread. |
| Subject | Photosynthesis discussion |
| Message | Lets discuss our learning about Photosynthesis this week in this thread. |
And I log out
And I log in as "student1"
And I am on "Science 101" course homepage
And I reply "Photosynethis discussion" post from "Study discussions" forum with:
And I reply "Photosynthesis discussion" post from "Study discussions" forum with:
| Message | Can anyone tell me which number is the mass number in the periodic table? |
And I log out
And I log in as "student2"
And I am on "Science 101" course homepage
And I follow "Study discussions"
And I follow "Photosynethis discussion"
And I follow "Photosynthesis discussion"
And I click on "Reply" "link" in the "//div[contains(concat(' ', normalize-space(@class), ' '), ' forumpost ')][contains(., 'Can anyone tell me which number is the mass number in the periodic table?')]" "xpath_element"
And I wait to be redirected
And I set the following fields to these values:
@ -48,17 +48,15 @@ Feature: Forum discussions can be split
Given I log in as "teacher1"
And I am on "Science 101" course homepage
And I follow "Study discussions"
And I follow "Photosynethis discussion"
And I follow "Photosynthesis discussion"
When I follow "Split"
And I set the following fields to these values:
| Discussion name | Mass number in periodic table |
And I press "Split"
Then I should see "Mass number in periodic table"
And I follow "Study discussions"
And I should see "Teacher 1" in the "Photosynethis" "table_row"
And I should see "Teacher 1" in the "Photosynthesis" "table_row"
# Confirm that the last post author has been updated.
And I should not see "Student 2" in the "Photosynethis" "table_row"
# Confirm that the corrent author has been shown for the new split discussion.
And I should not see "Student 2" in the "Photosynthesis" "table_row"
# Confirm that the current author has been shown for the new split discussion.
And I should see "Student 1" in the "Mass number in periodic table" "table_row"
# Confirm that the last post author has been updated for the new discussion.
And I should see "Student 2" in the "Mass number in periodic table" "table_row"

View File

@ -37,12 +37,12 @@ Feature: Users can choose to set start and end time for display of their discuss
And I follow "Test forum name"
And I should see "Discussion 2 timed"
And I should see "Discussion 3 timed"
And ".timedpost" "css_element" should exist
And "[data-region=timed-label]" "css_element" should exist
And I log out
And I log in as "student1"
When I am on "Course 1" course homepage
And I follow "Test forum name"
Then I should see "Discussion 1"
And I should not see "Discussion 2 timed"
And ".timedpost" "css_element" should not exist
And "[data-region=timed-label]" "css_element" should not exist
And I should see "Discussion 3 timed"

View File

@ -86,7 +86,7 @@ $displaymode = get_user_preferences('forum_displaymode', $CFG->forum_displaymode
$PAGE->set_context($forum->get_context());
$PAGE->set_title($forum->get_name());
$PAGE->add_body_class('forumtype-' . $forum->get_type());
$PAGE->add_body_class('forumtype-' . $forum->get_type() . ' reset-style');
$PAGE->set_heading($course->fullname);
$PAGE->set_button(forum_search_form($course, $search));

View File

@ -1,119 +0,0 @@
YUI.add('moodle-mod_forum-subscriptiontoggle', function (Y, NAME) {
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A utility to check whether the connection to the Moodle server is still
* active.
*
* @module moodle-core-subscriptiontoggle
* @package mod_forum
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @main moodle-mod_forum-subscriptiontoggle
*/
/**
* @namespace M.mod_forum
* @class subscriptiontoggle
*/
function SubscriptionToggle() {
SubscriptionToggle.superclass.constructor.apply(this, arguments);
}
var LOGNAME = 'moodle-mod_forum-subscriptiontoggle';
Y.extend(SubscriptionToggle, Y.Base, {
initializer: function() {
Y.delegate('click', this._toggleSubscription, Y.config.doc.body, '.discussionsubscription .discussiontoggle', this);
},
_toggleSubscription: function(e) {
var clickedLink = e.currentTarget;
Y.io(this.get('uri'), {
data: {
sesskey: M.cfg.sesskey,
forumid: clickedLink.getData('forumid'),
discussionid: clickedLink.getData('discussionid'),
includetext: clickedLink.getData('includetext')
},
context: this,
'arguments': {
clickedLink: clickedLink
},
on: {
complete: this._handleCompletion
}
});
// Prevent the standard browser behaviour now.
e.preventDefault();
},
_handleCompletion: function(tid, response, args) {
var responseObject;
// Attempt to parse the response into an object.
try {
responseObject = Y.JSON.parse(response.response);
if (responseObject.error) {
Y.use('moodle-core-notification-ajaxexception', function() {
return new M.core.ajaxException(responseObject);
});
return this;
}
} catch (error) {
Y.use('moodle-core-notification-exception', function() {
return new M.core.exception(error);
});
return this;
}
if (!responseObject.icon) {
Y.log('No icon received. Skipping the current value replacement', 'warn', LOGNAME);
return;
}
var container = args.clickedLink.ancestor('.discussionsubscription');
if (container) {
// We should just receive the new value for the table.
// Note: We do not need to escape the HTML here as it should be provided sanitised from the JS response already.
container.set('innerHTML', responseObject.icon);
}
}
}, {
NAME: 'subscriptionToggle',
ATTRS: {
/**
* The AJAX endpoint which controls the subscription toggle.
*
* @attribute uri
* @type String
* @default M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
*/
uri: {
value: M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
}
}
});
var NS = Y.namespace('M.mod_forum.subscriptiontoggle');
NS.init = function(config) {
return new SubscriptionToggle(config);
};
}, '@VERSION@', {"requires": ["base-base", "io-base"]});

View File

@ -1 +0,0 @@
YUI.add("moodle-mod_forum-subscriptiontoggle",function(e,t){function n(){n.superclass.constructor.apply(this,arguments)}var r="moodle-mod_forum-subscriptiontoggle";e.extend(n,e.Base,{initializer:function(){e.delegate("click",this._toggleSubscription,e.config.doc.body,".discussionsubscription .discussiontoggle",this)},_toggleSubscription:function(t){var n=t.currentTarget;e.io(this.get("uri"),{data:{sesskey:M.cfg.sesskey,forumid:n.getData("forumid"),discussionid:n.getData("discussionid"),includetext:n.getData("includetext")},context:this,arguments:{clickedLink:n},on:{complete:this._handleCompletion}}),t.preventDefault()},_handleCompletion:function(t,n,r){var i;try{i=e.JSON.parse(n.response);if(i.error)return e.use("moodle-core-notification-ajaxexception",function(){return new M.core.ajaxException(i)}),this}catch(s){return e.use("moodle-core-notification-exception",function(){return new M.core.exception(s)}),this}if(!i.icon)return;var o=r.clickedLink.ancestor(".discussionsubscription");o&&o.set("innerHTML",i.icon)}},{NAME:"subscriptionToggle",ATTRS:{uri:{value:M.cfg.wwwroot+"/mod/forum/subscribe_ajax.php"}}});var i=e.namespace("M.mod_forum.subscriptiontoggle");i.init=function(e){return new n(e)}},"@VERSION@",{requires:["base-base","io-base"]});

View File

@ -1,118 +0,0 @@
YUI.add('moodle-mod_forum-subscriptiontoggle', function (Y, NAME) {
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A utility to check whether the connection to the Moodle server is still
* active.
*
* @module moodle-core-subscriptiontoggle
* @package mod_forum
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @main moodle-mod_forum-subscriptiontoggle
*/
/**
* @namespace M.mod_forum
* @class subscriptiontoggle
*/
function SubscriptionToggle() {
SubscriptionToggle.superclass.constructor.apply(this, arguments);
}
var LOGNAME = 'moodle-mod_forum-subscriptiontoggle';
Y.extend(SubscriptionToggle, Y.Base, {
initializer: function() {
Y.delegate('click', this._toggleSubscription, Y.config.doc.body, '.discussionsubscription .discussiontoggle', this);
},
_toggleSubscription: function(e) {
var clickedLink = e.currentTarget;
Y.io(this.get('uri'), {
data: {
sesskey: M.cfg.sesskey,
forumid: clickedLink.getData('forumid'),
discussionid: clickedLink.getData('discussionid'),
includetext: clickedLink.getData('includetext')
},
context: this,
'arguments': {
clickedLink: clickedLink
},
on: {
complete: this._handleCompletion
}
});
// Prevent the standard browser behaviour now.
e.preventDefault();
},
_handleCompletion: function(tid, response, args) {
var responseObject;
// Attempt to parse the response into an object.
try {
responseObject = Y.JSON.parse(response.response);
if (responseObject.error) {
Y.use('moodle-core-notification-ajaxexception', function() {
return new M.core.ajaxException(responseObject);
});
return this;
}
} catch (error) {
Y.use('moodle-core-notification-exception', function() {
return new M.core.exception(error);
});
return this;
}
if (!responseObject.icon) {
return;
}
var container = args.clickedLink.ancestor('.discussionsubscription');
if (container) {
// We should just receive the new value for the table.
// Note: We do not need to escape the HTML here as it should be provided sanitised from the JS response already.
container.set('innerHTML', responseObject.icon);
}
}
}, {
NAME: 'subscriptionToggle',
ATTRS: {
/**
* The AJAX endpoint which controls the subscription toggle.
*
* @attribute uri
* @type String
* @default M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
*/
uri: {
value: M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
}
}
});
var NS = Y.namespace('M.mod_forum.subscriptiontoggle');
NS.init = function(config) {
return new SubscriptionToggle(config);
};
}, '@VERSION@', {"requires": ["base-base", "io-base"]});

View File

@ -1,10 +0,0 @@
{
"name": "moodle-mod_forum-subscriptiontoggle",
"builds": {
"moodle-mod_forum-subscriptiontoggle": {
"jsfiles": [
"toggle.js"
]
}
}
}

View File

@ -1,114 +0,0 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* A utility to check whether the connection to the Moodle server is still
* active.
*
* @module moodle-core-subscriptiontoggle
* @package mod_forum
* @copyright 2014 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @main moodle-mod_forum-subscriptiontoggle
*/
/**
* @namespace M.mod_forum
* @class subscriptiontoggle
*/
function SubscriptionToggle() {
SubscriptionToggle.superclass.constructor.apply(this, arguments);
}
var LOGNAME = 'moodle-mod_forum-subscriptiontoggle';
Y.extend(SubscriptionToggle, Y.Base, {
initializer: function() {
Y.delegate('click', this._toggleSubscription, Y.config.doc.body, '.discussionsubscription .discussiontoggle', this);
},
_toggleSubscription: function(e) {
var clickedLink = e.currentTarget;
Y.io(this.get('uri'), {
data: {
sesskey: M.cfg.sesskey,
forumid: clickedLink.getData('forumid'),
discussionid: clickedLink.getData('discussionid'),
includetext: clickedLink.getData('includetext')
},
context: this,
'arguments': {
clickedLink: clickedLink
},
on: {
complete: this._handleCompletion
}
});
// Prevent the standard browser behaviour now.
e.preventDefault();
},
_handleCompletion: function(tid, response, args) {
var responseObject;
// Attempt to parse the response into an object.
try {
responseObject = Y.JSON.parse(response.response);
if (responseObject.error) {
Y.use('moodle-core-notification-ajaxexception', function() {
return new M.core.ajaxException(responseObject);
});
return this;
}
} catch (error) {
Y.use('moodle-core-notification-exception', function() {
return new M.core.exception(error);
});
return this;
}
if (!responseObject.icon) {
Y.log('No icon received. Skipping the current value replacement', 'warn', LOGNAME);
return;
}
var container = args.clickedLink.ancestor('.discussionsubscription');
if (container) {
// We should just receive the new value for the table.
// Note: We do not need to escape the HTML here as it should be provided sanitised from the JS response already.
container.set('innerHTML', responseObject.icon);
}
}
}, {
NAME: 'subscriptionToggle',
ATTRS: {
/**
* The AJAX endpoint which controls the subscription toggle.
*
* @attribute uri
* @type String
* @default M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
*/
uri: {
value: M.cfg.wwwroot + '/mod/forum/subscribe_ajax.php'
}
}
});
var NS = Y.namespace('M.mod_forum.subscriptiontoggle');
NS.init = function(config) {
return new SubscriptionToggle(config);
};

View File

@ -1,8 +0,0 @@
{
"moodle-mod_forum-subscriptiontoggle": {
"requires": [
"base-base",
"io-base"
]
}
}