mirror of
https://github.com/moodle/moodle.git
synced 2025-02-22 19:06:51 +01:00
MDL-64956 mod_forum: Inpage reply
* Basic functionality for an inpage reply. With advanced link that takes you to the previous "Reply page". * Updated behat function to handle the additional step * Updated templates to have some identifiers on where one is storing the replies post * Updated discussion_post to use the new vault functions to get the corresponding records * Jumpto newly created post
This commit is contained in:
parent
9bcfd21bcd
commit
9b4f09bad2
1
mod/forum/amd/build/inpage_reply.min.js
vendored
Normal file
1
mod/forum/amd/build/inpage_reply.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core/templates","core/notification","mod_forum/repository","mod_forum/selectors"],function(a,b,c,d,e){var f={THREADED:2,NESTED:3,FLAT_OLDEST_FIRST:1,FLAT_NEWEST_FIRST:-1},g=function(g){g.on("click",e.post.inpageSubmitBtn,function(h){h.preventDefault();var i,j=a(h.currentTarget).parents(e.post.inpageReplyForm).get(0),k=j.elements.post.value,l=j.elements.reply.value,m=j.elements.subject.value,n=a(h.currentTarget).parents(e.post.forumContent),o=parseInt(g.find(e.post.modeSelect).get(0).value);d.addDiscussionPost(l,m,k).then(function(a){var c=a.post;switch(i=c.id,o){case f.THREADED:return b.render("mod_forum/forum_discussion_threaded_post",c);case f.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;return o!=f.FLAT_OLDEST_FIRST&&o!=f.FLAT_NEWEST_FIRST||(d=n.parents(e.post.repliesContainer).children().get(0)),void 0==d&&(d=n.siblings(e.post.repliesContainer).children().get(0)),o==f.FLAT_NEWEST_FIRST?b.prependNodeContents(d,a,c):b.appendNodeContents(d,a,c)}).then(function(){return n.find(e.post.inpageReplyContent).hide()}).then(function(){var b="[data-target='"+i+"-target']";a(b).length&&a("body").animate({scrollTop:a(b).offset().top-60})}).fail(c.exception)})};return{init:function(a){g(a)}}});
|
1
mod/forum/amd/build/posts_list.min.js
vendored
Normal file
1
mod/forum/amd/build/posts_list.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
define(["jquery","core/templates","core/notification","mod_forum/selectors","mod_forum/inpage_reply"],function(a,b,c,d,e){var f=function(e){e.on("click",d.post.inpageReplyLink,function(e){e.preventDefault();var f=a(e.currentTarget).parents(d.post.forumCoreContent),g=a(e.currentTarget).parents(d.post.forumContent),h={postid:a(g).data("post-id"),reply_url:a(e.currentTarget).attr("href"),sesskey:M.cfg.sesskey};if(g.find(d.post.inpageReplyContent).length){var i=g.find(d.post.inpageReplyContent);i.toggle(),i.is(":visible")&&i.find("textarea").focus()}else b.render("mod_forum/inpage_reply",h).then(function(a,c){return b.appendNodeContents(f,a,c)}).then(function(){g.find(d.post.inpageReplyContent).toggle().find("textarea").focus()}).fail(c.exception)})};return{init:function(a){f(a),e.init(a)}}});
|
2
mod/forum/amd/build/repository.min.js
vendored
2
mod/forum/amd/build/repository.min.js
vendored
@ -1 +1 @@
|
||||
define(["core/ajax"],function(a){var b=function(b,c,d){var e={methodname:"mod_forum_set_subscription_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]};return{setDiscussionSubscriptionState:b}});
|
||||
define(["core/ajax"],function(a){var b=function(b,c,d){var e={methodname:"mod_forum_set_subscription_state",args:{forumid:b,discussionid:c,targetstate:d}};return a.call([e])[0]},c=function(b,c,d){var e={methodname:"mod_forum_add_discussion_post",args:{postid:b,message:d,subject:c}};return a.call([e])[0]};return{setDiscussionSubscriptionState:b,addDiscussionPost:c}});
|
2
mod/forum/amd/build/selectors.min.js
vendored
2
mod/forum/amd/build/selectors.min.js
vendored
@ -1 +1 @@
|
||||
define([],function(){return{subscription:{toggle:"[data-type='subscription-toggle'][data-action='toggle']"},post:{post:'[data-region="post"]',action:'[data-region="post-action"]',actionsContainer:'[data-region="post-actions-container"]'}}});
|
||||
define([],function(){return{subscription:{toggle:"[data-type='subscription-toggle'][data-action='toggle']"},pin:{toggle:".pindiscussion [data-action='toggle']"},post:{post:'[data-region="post"]',action:'[data-region="post-action"]',actionsContainer:'[data-region="post-actions-container"]',forumCoreContent:"[data-region-content='forum-post-core']",forumContent:"[data-content='forum-post']",inpageReplyLink:"[data-action='collapsible-link']",inpageReplyContent:"[data-content='inpage-reply-content']",inpageReplyForm:"form[data-content='inpage-reply-form']",inpageSubmitBtn:"[data-action='forum-inpage-submit']",repliesContainer:"[data-region='replies-container']",modeSelect:"select[name='mode']"}}});
|
111
mod/forum/amd/src/inpage_reply.js
Normal file
111
mod/forum/amd/src/inpage_reply.js
Normal file
@ -0,0 +1,111 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* This module is the highest level module for the calendar. It is
|
||||
* responsible for initialising all of the components required for
|
||||
* the calendar to run. It also coordinates the interaction between
|
||||
* components by listening for and responding to different events
|
||||
* triggered within the calendar UI.
|
||||
*
|
||||
* @module mod_forum/posts_list
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Peter Dias
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'core/templates',
|
||||
'core/notification',
|
||||
'mod_forum/repository',
|
||||
'mod_forum/selectors',
|
||||
], function(
|
||||
$,
|
||||
Templates,
|
||||
Notification,
|
||||
Repository,
|
||||
Selectors
|
||||
) {
|
||||
|
||||
var DISPLAYCONSTANTS = {
|
||||
THREADED: 2,
|
||||
NESTED: 3,
|
||||
FLAT_OLDEST_FIRST: 1,
|
||||
FLAT_NEWEST_FIRST: -1
|
||||
};
|
||||
|
||||
var registerEventListeners = function(root) {
|
||||
root.on('click', Selectors.post.inpageSubmitBtn, function(e) {
|
||||
e.preventDefault();
|
||||
var form = $(e.currentTarget).parents(Selectors.post.inpageReplyForm).get(0);
|
||||
var message = form.elements.post.value;
|
||||
var postid = form.elements.reply.value;
|
||||
var subject = form.elements.subject.value;
|
||||
var currentRoot = $(e.currentTarget).parents(Selectors.post.forumContent);
|
||||
var mode = parseInt(root.find(Selectors.post.modeSelect).get(0).value);
|
||||
var newid;
|
||||
|
||||
Repository.addDiscussionPost(postid, subject, message)
|
||||
.then(function(context) {
|
||||
var post = context.post;
|
||||
newid = post.id;
|
||||
switch (mode) {
|
||||
case DISPLAYCONSTANTS.THREADED:
|
||||
return Templates.render('mod_forum/forum_discussion_threaded_post', post);
|
||||
case DISPLAYCONSTANTS.NESTED:
|
||||
return Templates.render('mod_forum/forum_discussion_nested_post', post);
|
||||
default:
|
||||
return Templates.render('mod_forum/forum_discussion_post', post);
|
||||
}
|
||||
})
|
||||
.then(function(html, js) {
|
||||
var repliesnode;
|
||||
|
||||
// Try and get the replies-container which can either be a sibling OR parent if it's flat
|
||||
if (mode == DISPLAYCONSTANTS.FLAT_OLDEST_FIRST || mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {
|
||||
repliesnode = currentRoot.parents(Selectors.post.repliesContainer).children().get(0);
|
||||
}
|
||||
|
||||
if (repliesnode == undefined) {
|
||||
repliesnode = currentRoot.siblings(Selectors.post.repliesContainer).children().get(0);
|
||||
}
|
||||
|
||||
if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {
|
||||
return Templates.prependNodeContents(repliesnode, html, js);
|
||||
} else {
|
||||
return Templates.appendNodeContents(repliesnode, html, js);
|
||||
}
|
||||
})
|
||||
.then(function() {
|
||||
return currentRoot.find(Selectors.post.inpageReplyContent).hide();
|
||||
})
|
||||
.then(function() {
|
||||
var target = "[data-target='" + newid + "-target']";
|
||||
if ($(target).length) {
|
||||
$('body').animate({scrollTop: $(target).offset().top - 60});
|
||||
}
|
||||
return;
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: function(root) {
|
||||
registerEventListeners(root);
|
||||
|
||||
}
|
||||
};
|
||||
});
|
78
mod/forum/amd/src/posts_list.js
Normal file
78
mod/forum/amd/src/posts_list.js
Normal file
@ -0,0 +1,78 @@
|
||||
// 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/>.
|
||||
|
||||
/**
|
||||
* This module is the highest level module for the calendar. It is
|
||||
* responsible for initialising all of the components required for
|
||||
* the calendar to run. It also coordinates the interaction between
|
||||
* components by listening for and responding to different events
|
||||
* triggered within the calendar UI.
|
||||
*
|
||||
* @module mod_forum/posts_list
|
||||
* @package mod_forum
|
||||
* @copyright 2019 Peter Dias
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
define([
|
||||
'jquery',
|
||||
'core/templates',
|
||||
'core/notification',
|
||||
'mod_forum/selectors',
|
||||
'mod_forum/inpage_reply',
|
||||
], function(
|
||||
$,
|
||||
Templates,
|
||||
Notification,
|
||||
Selectors,
|
||||
InPageReply
|
||||
) {
|
||||
|
||||
var registerEventListeners = function(root) {
|
||||
root.on('click', Selectors.post.inpageReplyLink, function(e) {
|
||||
e.preventDefault();
|
||||
var currentTarget = $(e.currentTarget).parents(Selectors.post.forumCoreContent);
|
||||
var currentRoot = $(e.currentTarget).parents(Selectors.post.forumContent);
|
||||
var context = {
|
||||
postid: $(currentRoot).data('post-id'),
|
||||
reply_url: $(e.currentTarget).attr('href'),
|
||||
sesskey: M.cfg.sesskey
|
||||
};
|
||||
|
||||
if (!currentRoot.find(Selectors.post.inpageReplyContent).length) {
|
||||
Templates.render('mod_forum/inpage_reply', context)
|
||||
.then(function(html, js) {
|
||||
return Templates.appendNodeContents(currentTarget, html, js);
|
||||
})
|
||||
.then(function() {
|
||||
currentRoot.find(Selectors.post.inpageReplyContent).toggle().find('textarea').focus();
|
||||
})
|
||||
.fail(Notification.exception);
|
||||
} else {
|
||||
var form = currentRoot.find(Selectors.post.inpageReplyContent);
|
||||
form.toggle();
|
||||
if (form.is(':visible')) {
|
||||
form.find('textarea').focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
init: function(root) {
|
||||
registerEventListeners(root);
|
||||
InPageReply.init(root);
|
||||
}
|
||||
};
|
||||
});
|
@ -43,7 +43,21 @@ define(['core/ajax'], function(Ajax) {
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
|
||||
var addDiscussionPost = function(postid, subject, message) {
|
||||
var request = {
|
||||
methodname: 'mod_forum_add_discussion_post',
|
||||
args: {
|
||||
postid: postid,
|
||||
message: message,
|
||||
subject: subject
|
||||
}
|
||||
};
|
||||
|
||||
return Ajax.call([request])[0];
|
||||
};
|
||||
|
||||
return {
|
||||
setDiscussionSubscriptionState: setDiscussionSubscriptionState,
|
||||
addDiscussionPost: addDiscussionPost
|
||||
};
|
||||
});
|
||||
|
@ -26,10 +26,21 @@ define([], function() {
|
||||
subscription: {
|
||||
toggle: "[data-type='subscription-toggle'][data-action='toggle']",
|
||||
},
|
||||
pin: {
|
||||
toggle: ".pindiscussion [data-action='toggle']",
|
||||
},
|
||||
post: {
|
||||
post: '[data-region="post"]',
|
||||
action: '[data-region="post-action"]',
|
||||
actionsContainer: '[data-region="post-actions-container"]'
|
||||
actionsContainer: '[data-region="post-actions-container"]',
|
||||
forumCoreContent: "[data-region-content='forum-post-core']",
|
||||
forumContent: "[data-content='forum-post']",
|
||||
inpageReplyLink: "[data-action='collapsible-link']",
|
||||
inpageReplyContent: "[data-content='inpage-reply-content']",
|
||||
inpageReplyForm: "form[data-content='inpage-reply-form']",
|
||||
inpageSubmitBtn: "[data-action='forum-inpage-submit']",
|
||||
repliesContainer: "[data-region='replies-container']",
|
||||
modeSelect: "select[name='mode']",
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -93,6 +93,7 @@ $functions = array(
|
||||
'classpath' => 'mod/forum/externallib.php',
|
||||
'description' => 'Create new posts into an existing discussion.',
|
||||
'type' => 'write',
|
||||
'ajax' => true,
|
||||
'capabilities' => 'mod/forum:replypost',
|
||||
'services' => array(MOODLE_OFFICIAL_MOBILE_SERVICE)
|
||||
),
|
||||
|
@ -27,6 +27,8 @@ defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once("$CFG->libdir/externallib.php");
|
||||
|
||||
use mod_forum\local\exporters\post as post_exporter;
|
||||
|
||||
class mod_forum_external extends external_api {
|
||||
|
||||
/**
|
||||
@ -917,6 +919,16 @@ class mod_forum_external extends external_api {
|
||||
global $DB, $CFG, $USER;
|
||||
require_once($CFG->dirroot . "/mod/forum/lib.php");
|
||||
|
||||
// Get all the factories that are required.
|
||||
$vaultfactory = mod_forum\local\container::get_vault_factory();
|
||||
$entityfactory = mod_forum\local\container::get_entity_factory();
|
||||
$datamapperfactory = mod_forum\local\container::get_legacy_data_mapper_factory();
|
||||
$managerfactory = mod_forum\local\container::get_manager_factory();
|
||||
$discussionvault = $vaultfactory->get_discussion_vault();
|
||||
$forumvault = $vaultfactory->get_forum_vault();
|
||||
$discussiondatamapper = $datamapperfactory->get_discussion_data_mapper();
|
||||
$forumdatamapper = $datamapperfactory->get_forum_data_mapper();
|
||||
|
||||
$params = self::validate_parameters(self::add_discussion_post_parameters(),
|
||||
array(
|
||||
'postid' => $postid,
|
||||
@ -932,14 +944,18 @@ class mod_forum_external extends external_api {
|
||||
throw new moodle_exception('invalidparentpostid', 'forum');
|
||||
}
|
||||
|
||||
if (!$discussion = $DB->get_record("forum_discussions", array("id" => $parent->discussion))) {
|
||||
if (!$discussion = $discussionvault->get_from_id($parent->discussion)) {
|
||||
throw new moodle_exception('notpartofdiscussion', 'forum');
|
||||
}
|
||||
|
||||
// Request and permission validation.
|
||||
$forum = $DB->get_record('forum', array('id' => $discussion->forum), '*', MUST_EXIST);
|
||||
list($course, $cm) = get_course_and_cm_from_instance($forum, 'forum');
|
||||
$forum = $forumvault->get_from_id($discussion->get_forum_id());
|
||||
$capabilitymanager = $managerfactory->get_capability_manager($forum);
|
||||
$course = $forum->get_course_record();
|
||||
$cm = $forum->get_course_module_record();
|
||||
|
||||
$discussionrecord = $discussiondatamapper->to_legacy_object($discussion);
|
||||
$forumrecord = $forumdatamapper->to_legacy_object($forum);
|
||||
$context = context_module::instance($cm->id);
|
||||
self::validate_context($context);
|
||||
|
||||
@ -975,16 +991,16 @@ class mod_forum_external extends external_api {
|
||||
$options[$name] = $value;
|
||||
}
|
||||
|
||||
if (!forum_user_can_post($forum, $discussion, $USER, $cm, $course, $context)) {
|
||||
if (!$capabilitymanager->can_post_in_discussion($USER, $discussion)) {
|
||||
throw new moodle_exception('nopostforum', 'forum');
|
||||
}
|
||||
|
||||
$thresholdwarning = forum_check_throttling($forum, $cm);
|
||||
$thresholdwarning = forum_check_throttling($forumrecord, $cm);
|
||||
forum_check_blocking_threshold($thresholdwarning);
|
||||
|
||||
// Create the post.
|
||||
$post = new stdClass();
|
||||
$post->discussion = $discussion->id;
|
||||
$post->discussion = $discussion->get_id();
|
||||
$post->parent = $parent->id;
|
||||
$post->subject = $params['subject'];
|
||||
$post->message = $params['message'];
|
||||
@ -1004,33 +1020,41 @@ class mod_forum_external extends external_api {
|
||||
'context' => $context,
|
||||
'objectid' => $post->id,
|
||||
'other' => array(
|
||||
'discussionid' => $discussion->id,
|
||||
'forumid' => $forum->id,
|
||||
'forumtype' => $forum->type,
|
||||
'discussionid' => $discussion->get_id(),
|
||||
'forumid' => $forum->get_id(),
|
||||
'forumtype' => $forum->get_type(),
|
||||
)
|
||||
);
|
||||
$event = \mod_forum\event\post_created::create($params);
|
||||
$event->add_record_snapshot('forum_posts', $post);
|
||||
$event->add_record_snapshot('forum_discussions', $discussion);
|
||||
$event->add_record_snapshot('forum_discussions', $discussionrecord);
|
||||
$event->trigger();
|
||||
|
||||
// Update completion state.
|
||||
$completion = new completion_info($course);
|
||||
if ($completion->is_enabled($cm) &&
|
||||
($forum->completionreplies || $forum->completionposts)) {
|
||||
($forum->get_completion_replies() || $forum->get_completion_posts())) {
|
||||
$completion->update_state($cm, COMPLETION_COMPLETE);
|
||||
}
|
||||
|
||||
$settings = new stdClass();
|
||||
$settings->discussionsubscribe = $options['discussionsubscribe'];
|
||||
forum_post_subscription($settings, $forum, $discussion);
|
||||
forum_post_subscription($settings, $forumrecord, $discussionrecord);
|
||||
} else {
|
||||
throw new moodle_exception('couldnotadd', 'forum');
|
||||
}
|
||||
|
||||
|
||||
$builderfactory = \mod_forum\local\container::get_builder_factory();
|
||||
$exportedpostsbuilder = $builderfactory->get_exported_posts_builder();
|
||||
$postentity = $entityfactory->get_post_from_stdClass($post);
|
||||
$exportedposts = $exportedpostsbuilder->build($USER, [$forum], [$discussion], [$postentity]);
|
||||
$exportedpost = $exportedposts[0];
|
||||
|
||||
$result = array();
|
||||
$result['postid'] = $postid;
|
||||
$result['warnings'] = $warnings;
|
||||
$result['post'] = $exportedpost;
|
||||
return $result;
|
||||
}
|
||||
|
||||
@ -1044,7 +1068,8 @@ class mod_forum_external extends external_api {
|
||||
return new external_single_structure(
|
||||
array(
|
||||
'postid' => new external_value(PARAM_INT, 'new post id'),
|
||||
'warnings' => new external_warnings()
|
||||
'warnings' => new external_warnings(),
|
||||
'post' => post_exporter::get_read_structure()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ $string['addanewdiscussion'] = 'Add a new discussion topic';
|
||||
$string['addanewquestion'] = 'Add a new question';
|
||||
$string['addanewtopic'] = 'Add a new topic';
|
||||
$string['advancedsearch'] = 'Advanced search';
|
||||
$string['advanced'] = 'Advanced';
|
||||
$string['allforums'] = 'All forums';
|
||||
$string['allowdiscussions'] = 'Can a {$a} post to this forum?';
|
||||
$string['allowsallsubscribe'] = 'This forum allows everyone to choose whether to subscribe or not';
|
||||
@ -525,6 +526,7 @@ $string['replies'] = 'Replies';
|
||||
$string['repliesmany'] = '{$a} replies so far';
|
||||
$string['repliesone'] = '{$a} reply so far';
|
||||
$string['reply'] = 'Reply';
|
||||
$string['replyplaceholder'] = 'Write your reply...';
|
||||
$string['replyforum'] = 'Reply to forum';
|
||||
$string['replytopostbyemail'] = 'You can reply to this via email.';
|
||||
$string['replytouser'] = 'Use email address in reply';
|
||||
|
@ -34,6 +34,8 @@ $prune = optional_param('prune', 0, PARAM_INT);
|
||||
$name = optional_param('name', '', PARAM_CLEAN);
|
||||
$confirm = optional_param('confirm', 0, PARAM_INT);
|
||||
$groupid = optional_param('groupid', null, PARAM_INT);
|
||||
$subject = optional_param('subject', '', PARAM_TEXT);
|
||||
$prefilledpost = optional_param('post', '', PARAM_TEXT);
|
||||
|
||||
$PAGE->set_url('/mod/forum/post.php', array(
|
||||
'reply' => $reply,
|
||||
@ -163,9 +165,9 @@ if (!empty($forum)) {
|
||||
$post->forum = $forum->id;
|
||||
$post->discussion = 0; // Ie discussion # not defined yet.
|
||||
$post->parent = 0;
|
||||
$post->subject = '';
|
||||
$post->subject = $subject;
|
||||
$post->userid = $USER->id;
|
||||
$post->message = '';
|
||||
$post->message = $prefilledpost;
|
||||
$post->messageformat = editors_get_preferred_format();
|
||||
$post->messagetrust = 0;
|
||||
$post->groupid = $groupid;
|
||||
@ -249,10 +251,10 @@ if (!empty($forum)) {
|
||||
$post->forum = $forum->id;
|
||||
$post->discussion = $parent->discussion;
|
||||
$post->parent = $parent->id;
|
||||
$post->subject = $parent->subject;
|
||||
$post->subject = $subject ? $subject : $parent->subject;
|
||||
$post->userid = $USER->id;
|
||||
$post->message = '';
|
||||
$post->parentpostauthor = $parent->userid;
|
||||
$post->message = $prefilledpost;
|
||||
$canreplyprivately = $capabilitymanager->can_reply_privately_to_post($USER, $parententity);
|
||||
|
||||
$post->groupid = ($discussion->groupid == -1) ? 0 : $discussion->groupid;
|
||||
|
@ -58,7 +58,6 @@
|
||||
{{$discussion_list_header}}
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"> </th>
|
||||
<th scope="col"> </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>
|
||||
@ -75,6 +74,7 @@
|
||||
{{/forum.userstate.tracked}}
|
||||
{{/forum.capabilities.viewdiscussions}}
|
||||
<th scope="col" class="lastpost">{{#str}}lastpost, mod_forum{{/str}}</th>
|
||||
<th scope="col"> </th>
|
||||
{{#forum.capabilities.subscribe}}
|
||||
<th scope="col" class="discussionsubscription"></th>
|
||||
{{/forum.capabilities.subscribe}}
|
||||
@ -91,27 +91,6 @@
|
||||
{{#pix}}i/pinned, mod_forum, {{#str}}discussionpinned, mod_forum{{/str}}{{/pix}}
|
||||
{{/discussion.pinned}}
|
||||
</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="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>
|
||||
@ -208,6 +187,27 @@
|
||||
</div>
|
||||
{{/latestpostid}}
|
||||
</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">
|
||||
{{#discussion}}
|
||||
{{> mod_forum/discussion_subscription_toggle}}
|
||||
|
@ -30,7 +30,7 @@
|
||||
}
|
||||
}}
|
||||
|
||||
<div id="discussion-container-{{uniqid}}">
|
||||
<div id="discussion-container-{{uniqid}}" data-content="forum-discussion">
|
||||
{{#html}}
|
||||
{{{subscribe}}}
|
||||
{{{neighbourlinks}}}
|
||||
@ -52,8 +52,10 @@
|
||||
{{#html.neighbourlinks}}{{{.}}}{{/html.neighbourlinks}}
|
||||
</div>
|
||||
{{#js}}
|
||||
require(['jquery', 'mod_forum/discussion'], function($, Discussion) {
|
||||
var root = $('#discussion-container-{{uniqid}}');
|
||||
require(['jquery', 'mod_forum/discussion', 'mod_forum/posts_list'], function($, Discussion, PostsList) {
|
||||
var root = $("[data-content='forum-discussion']");
|
||||
Discussion.init(root);
|
||||
PostsList.init(root);
|
||||
var root = $('#discussion-container-{{uniqid}}');
|
||||
});
|
||||
{{/js}}
|
||||
|
@ -34,15 +34,16 @@
|
||||
class="relativelink mb-2"
|
||||
data-post-id="{{id}}"
|
||||
data-region="post"
|
||||
data-target="{{id}}-target"
|
||||
tabindex="-1"
|
||||
aria-labelledby="post-header-{{id}}"
|
||||
aria-describedby="post-content-{{id}}"
|
||||
>
|
||||
|
||||
<!-- The firstpost and starter classes below aren't used for anything other than to identify the first post in behat -->
|
||||
<div
|
||||
class="d-flex border p-2 mb-2 forumpost {{#unread}}unread{{/unread}} {{#firstpost}}firstpost starter{{/firstpost}}"
|
||||
aria-label='{{#str}} postbyuser, mod_forum, {"post": "{{subject}}", "user": "{{author.fullname}}"} {{/str}}'
|
||||
data-post-id="{{id}}" data-content="forum-post"
|
||||
>
|
||||
{{#isfirstunread}}<a id="unread" aria-hidden="true"></a>{{/isfirstunread}}
|
||||
{{^isdeleted}}
|
||||
@ -69,8 +70,8 @@
|
||||
{{/author}}
|
||||
{{/isdeleted}}
|
||||
|
||||
<div class="d-flex flex-column ml-2 w-100">
|
||||
<header id="post-header-{{id}}" class="mb-2 header row">
|
||||
<div class="d-flex flex-column ml-2 w-100" data-region-content="forum-post-core">
|
||||
<header class="mb-2 header row">
|
||||
{{#parentauthorname}}
|
||||
<span class="sr-only">{{#str}} inreplyto, mod_forum, {{.}} {{/str}}</span>
|
||||
{{/parentauthorname}}
|
||||
@ -241,6 +242,9 @@
|
||||
href="{{{urls.reply}}}"
|
||||
class="btn btn-link"
|
||||
role="menuitem"
|
||||
data-post-id="{{id}}"
|
||||
data-action="collapsible-link"
|
||||
title="{{#str}} reply, mod_forum {{/str}}"
|
||||
>
|
||||
{{#str}} reply, mod_forum {{/str}}
|
||||
</a>
|
||||
@ -266,13 +270,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-region="replies-container">
|
||||
{{$replies}}
|
||||
<div>
|
||||
{{#hasreplies}}
|
||||
<div>
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_post }}
|
||||
{{/replies}}
|
||||
{{/hasreplies}}
|
||||
</div>
|
||||
{{/replies}}
|
||||
</div>
|
||||
</article>
|
||||
|
@ -33,6 +33,7 @@
|
||||
class="mb-2"
|
||||
data-post-id="{{id}}"
|
||||
data-region="post"
|
||||
data-target="{{id}}-target"
|
||||
tabindex="-1"
|
||||
>
|
||||
<a href="{{{urls.viewisolated}}}">{{subject}}</a>
|
||||
@ -42,9 +43,11 @@
|
||||
</address>
|
||||
{{/isdeleted}}
|
||||
|
||||
<div class="indent">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_threaded_post }}
|
||||
{{/replies}}
|
||||
<div data-region="replies-container">
|
||||
<div class="indent">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_threaded_post }}
|
||||
{{/replies}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -34,7 +34,7 @@
|
||||
{{< mod_forum/forum_discussion_post }}
|
||||
{{$replies}}
|
||||
<!-- The forumthread class is only added for behat -->
|
||||
<div class="indent forumthread">
|
||||
<div class="indent forumthread post-replies">
|
||||
{{#replies}}
|
||||
{{> mod_forum/forum_discussion_threaded_post }}
|
||||
{{/replies}}
|
||||
|
56
mod/forum/templates/inpage_reply.mustache
Normal file
56
mod/forum/templates/inpage_reply.mustache
Normal file
@ -0,0 +1,56 @@
|
||||
{{!
|
||||
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/forum_post_email_htmlemail
|
||||
|
||||
Template which defines a forum post for sending in a single-post HTML email.
|
||||
|
||||
Classes required for JS:
|
||||
* none
|
||||
|
||||
Data attributes required for JS:
|
||||
* none
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div class="row" data-content="inpage-reply-content" style="display: none;">
|
||||
<div class="card card-body">
|
||||
<form data-post-id="{{postid}}" id="inpage-reply-{{postid}}" data-content="inpage-reply-form" action="{{{reply_url}}}">
|
||||
<div class="row pb-1">
|
||||
<span>
|
||||
<textarea rows="5" name="post" title="post" class="w-100" placeholder="{{#str}} replyplaceholder, forum {{/str}}"></textarea>
|
||||
</span>
|
||||
<input type="hidden" name="subject" value="Re: Post reply"/>
|
||||
<input type="hidden" name="reply" value="{{postid}}"/>
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}"/>
|
||||
</div>
|
||||
<div class="row">
|
||||
<button class="btn btn-primary" title="{{#str}} submit, core {{/str}}" data-action="forum-inpage-submit">
|
||||
{{#str}} submit, core {{/str}}
|
||||
</button>
|
||||
<button class="btn btn-secondary" title="{{#str}} cancel, core {{/str}}" data-action="collapsible-link">
|
||||
{{#str}} cancel, core {{/str}}
|
||||
</button>
|
||||
<button title="{{#str}} advanced, forum {{/str}}" data-action="forum-advanced-reply" class="btn btn-link float-right" type="submit">
|
||||
{{#str}} advanced, forum {{/str}}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -74,6 +74,7 @@ class behat_mod_forum extends behat_base {
|
||||
$this->execute('behat_general::click_link', $this->escape($forumname));
|
||||
$this->execute('behat_general::click_link', $this->escape($postsubject));
|
||||
$this->execute('behat_general::click_link', get_string('reply', 'forum'));
|
||||
$this->execute('behat_general::click_link', get_string('advanced', 'forum'));
|
||||
|
||||
// Fill form and post.
|
||||
$this->execute('behat_forms::i_set_the_following_fields_to_these_values', $table);
|
||||
@ -82,6 +83,27 @@ class behat_mod_forum extends behat_base {
|
||||
$this->execute('behat_general::i_wait_to_be_redirected');
|
||||
}
|
||||
|
||||
/**
|
||||
* Inpage Reply - adds a reply to the specified post of the specified forum. The step begins from the forum's page or from the forum's course page.
|
||||
*
|
||||
* @Given /^I reply "(?P<post_subject_string>(?:[^"]|\\")*)" post from "(?P<forum_name_string>(?:[^"]|\\")*)" forum using an inpage reply with:$/
|
||||
* @param string $postsubject The subject of the post
|
||||
* @param string $forumname The forum name
|
||||
* @param TableNode $table
|
||||
*/
|
||||
public function i_reply_post_from_forum_using_an_inpage_reply_with($postsubject, $forumname, TableNode $table) {
|
||||
|
||||
// Navigate to forum.
|
||||
$this->execute('behat_general::click_link', $this->escape($forumname));
|
||||
$this->execute('behat_general::click_link', $this->escape($postsubject));
|
||||
$this->execute('behat_general::click_link', get_string('reply', 'forum'));
|
||||
|
||||
// Fill form and post.
|
||||
$this->execute('behat_forms::i_set_the_following_fields_to_these_values', $table);
|
||||
|
||||
$this->execute('behat_forms::press_button', get_string('submit', 'core'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the steps list to add a new discussion to a forum.
|
||||
*
|
||||
|
@ -1,4 +1,4 @@
|
||||
@mod @mod_forum
|
||||
@mod @mod_forum @javascript
|
||||
Feature: Students can choose from 4 discussion display options and their choice is remembered
|
||||
In order to read forum posts in a suitable view
|
||||
As a user
|
||||
|
34
mod/forum/tests/behat/inpage_reply.feature
Normal file
34
mod/forum/tests/behat/inpage_reply.feature
Normal file
@ -0,0 +1,34 @@
|
||||
@mod @mod_forum @javascript
|
||||
Feature: Students can reply to a discussion in page.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@example.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum name |
|
||||
| Description | Test forum description |
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Discussion 1 |
|
||||
| Message | Discussion contents 1, first message |
|
||||
And I add a new discussion to "Test forum name" forum with:
|
||||
| Subject | Discussion 2 |
|
||||
| Message | Discussion contents 2, first message |
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
|
||||
Scenario: Confirm inpage replies work
|
||||
Given I reply "Discussion 2" post from "Test forum name" forum using an inpage reply with:
|
||||
| post | Discussion contents 1, third message |
|
||||
Then I should see "Discussion contents 1, third message"
|
||||
When I reload the page
|
||||
Then I should see "Discussion contents 1, third message"
|
Loading…
x
Reference in New Issue
Block a user