1 |
efrain |
1 |
// This file is part of Moodle - http://moodle.org/
|
|
|
2 |
//
|
|
|
3 |
// Moodle is free software: you can redistribute it and/or modify
|
|
|
4 |
// it under the terms of the GNU General Public License as published by
|
|
|
5 |
// the Free Software Foundation, either version 3 of the License, or
|
|
|
6 |
// (at your option) any later version.
|
|
|
7 |
//
|
|
|
8 |
// Moodle is distributed in the hope that it will be useful,
|
|
|
9 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
10 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
11 |
// GNU General Public License for more details.
|
|
|
12 |
//
|
|
|
13 |
// You should have received a copy of the GNU General Public License
|
|
|
14 |
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
15 |
|
|
|
16 |
/**
|
|
|
17 |
* This module handles the in page replying to forum posts.
|
|
|
18 |
*
|
|
|
19 |
* @module mod_forum/inpage_reply
|
|
|
20 |
* @copyright 2019 Peter Dias
|
|
|
21 |
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
22 |
*/
|
|
|
23 |
define([
|
|
|
24 |
'jquery',
|
|
|
25 |
'core/templates',
|
|
|
26 |
'core/notification',
|
|
|
27 |
'mod_forum/repository',
|
|
|
28 |
'mod_forum/selectors',
|
|
|
29 |
'core_form/changechecker',
|
|
|
30 |
], function(
|
|
|
31 |
$,
|
|
|
32 |
Templates,
|
|
|
33 |
Notification,
|
|
|
34 |
Repository,
|
|
|
35 |
Selectors,
|
|
|
36 |
FormChangeChecker
|
|
|
37 |
) {
|
|
|
38 |
|
|
|
39 |
var DISPLAYCONSTANTS = {
|
|
|
40 |
NESTED_V2: 4,
|
|
|
41 |
THREADED: 2,
|
|
|
42 |
NESTED: 3,
|
|
|
43 |
FLAT_OLDEST_FIRST: 1,
|
|
|
44 |
FLAT_NEWEST_FIRST: -1
|
|
|
45 |
};
|
|
|
46 |
|
|
|
47 |
var EVENTS = {
|
|
|
48 |
POST_CREATED: 'mod_forum-post-created'
|
|
|
49 |
};
|
|
|
50 |
|
|
|
51 |
/**
|
|
|
52 |
* Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.
|
|
|
53 |
* @type {Object}
|
|
|
54 |
*/
|
|
|
55 |
var CONTENT_FORMATS = {
|
|
|
56 |
MOODLE: 0
|
|
|
57 |
};
|
|
|
58 |
/**
|
|
|
59 |
* Show the loading icon for the submit button.
|
|
|
60 |
*
|
|
|
61 |
* @param {Object} button The submit button element
|
|
|
62 |
*/
|
|
|
63 |
var showSubmitButtonLoadingIcon = function(button) {
|
|
|
64 |
var textContainer = button.find(Selectors.post.inpageSubmitBtnText);
|
|
|
65 |
var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);
|
|
|
66 |
var width = button.outerWidth();
|
|
|
67 |
// Fix the width so that the button size doesn't change when we show the loading icon.
|
|
|
68 |
button.css('width', width);
|
|
|
69 |
textContainer.addClass('hidden');
|
|
|
70 |
loadingIconContainer.removeClass('hidden');
|
|
|
71 |
};
|
|
|
72 |
|
|
|
73 |
/**
|
|
|
74 |
* Hide the loading icon for the submit button.
|
|
|
75 |
*
|
|
|
76 |
* @param {Object} button The submit button element
|
|
|
77 |
*/
|
|
|
78 |
var hideSubmitButtonLoadingIcon = function(button) {
|
|
|
79 |
var textContainer = button.find(Selectors.post.inpageSubmitBtnText);
|
|
|
80 |
var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);
|
|
|
81 |
// Reset the width back to it's default.
|
|
|
82 |
button.css('width', '');
|
|
|
83 |
textContainer.removeClass('hidden');
|
|
|
84 |
loadingIconContainer.addClass('hidden');
|
|
|
85 |
};
|
|
|
86 |
|
|
|
87 |
/**
|
|
|
88 |
* Register the event listeners for the submit/cancel buttons of the in page reply.
|
|
|
89 |
*
|
|
|
90 |
* @param {Object} root The discussion container element.
|
|
|
91 |
*/
|
|
|
92 |
var registerEventListeners = function(root) {
|
|
|
93 |
root.on('click', Selectors.post.inpageSubmitBtn, function(e) {
|
|
|
94 |
e.preventDefault();
|
|
|
95 |
var submitButton = $(e.currentTarget);
|
|
|
96 |
var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);
|
|
|
97 |
var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);
|
|
|
98 |
var message = form.elements.post.value.trim();
|
|
|
99 |
// For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).
|
|
|
100 |
// In the future, other formats should be supported, letting users to use their preferred editor and format.
|
|
|
101 |
var messageformat = CONTENT_FORMATS.MOODLE;
|
|
|
102 |
// The message post will be converted from messageformat to FORMAT_HTML.
|
|
|
103 |
var topreferredformat = true;
|
|
|
104 |
var postid = form.elements.reply.value;
|
|
|
105 |
var subject = form.elements.subject.value;
|
|
|
106 |
var currentRoot = submitButton.closest(Selectors.post.post);
|
|
|
107 |
var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;
|
|
|
108 |
var modeSelector = root.find(Selectors.post.modeSelect);
|
|
|
109 |
var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;
|
|
|
110 |
var newid;
|
|
|
111 |
|
|
|
112 |
if (message.length) {
|
|
|
113 |
showSubmitButtonLoadingIcon(submitButton);
|
|
|
114 |
allButtons.prop('disabled', true);
|
|
|
115 |
|
|
|
116 |
Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)
|
|
|
117 |
.then(function(context) {
|
|
|
118 |
var message = context.messages.reduce(function(carry, message) {
|
|
|
119 |
if (message.type == 'success') {
|
|
|
120 |
carry += '<p>' + message.message + '</p>';
|
|
|
121 |
}
|
|
|
122 |
return carry;
|
|
|
123 |
}, '');
|
|
|
124 |
Notification.addNotification({
|
|
|
125 |
message: message,
|
|
|
126 |
type: "success"
|
|
|
127 |
});
|
|
|
128 |
|
|
|
129 |
return context;
|
|
|
130 |
})
|
|
|
131 |
.then(function(context) {
|
|
|
132 |
form.reset();
|
|
|
133 |
var post = context.post;
|
|
|
134 |
newid = post.id;
|
|
|
135 |
|
|
|
136 |
switch (mode) {
|
|
|
137 |
case DISPLAYCONSTANTS.NESTED_V2:
|
|
|
138 |
var capabilities = post.capabilities;
|
|
|
139 |
var currentAuthorName = currentRoot.children()
|
|
|
140 |
.not(Selectors.post.repliesContainer)
|
|
|
141 |
.find(Selectors.post.authorName)
|
|
|
142 |
.text();
|
|
|
143 |
post.parentauthorname = currentAuthorName;
|
|
|
144 |
post.showactionmenu = capabilities.view ||
|
|
|
145 |
capabilities.controlreadstatus ||
|
|
|
146 |
capabilities.edit ||
|
|
|
147 |
capabilities.split ||
|
|
|
148 |
capabilities.delete ||
|
|
|
149 |
capabilities.export ||
|
|
|
150 |
post.urls.viewparent;
|
|
|
151 |
return Templates.render('mod_forum/forum_discussion_nested_v2_post_reply', post);
|
|
|
152 |
case DISPLAYCONSTANTS.THREADED:
|
|
|
153 |
return Templates.render('mod_forum/forum_discussion_threaded_post', post);
|
|
|
154 |
case DISPLAYCONSTANTS.NESTED:
|
|
|
155 |
return Templates.render('mod_forum/forum_discussion_nested_post', post);
|
|
|
156 |
default:
|
|
|
157 |
return Templates.render('mod_forum/forum_discussion_post', post);
|
|
|
158 |
}
|
|
|
159 |
})
|
|
|
160 |
.then(function(html, js) {
|
|
|
161 |
var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();
|
|
|
162 |
|
|
|
163 |
if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {
|
|
|
164 |
return Templates.prependNodeContents(repliesnode, html, js);
|
|
|
165 |
} else {
|
|
|
166 |
return Templates.appendNodeContents(repliesnode, html, js);
|
|
|
167 |
}
|
|
|
168 |
})
|
|
|
169 |
.then(function() {
|
|
|
170 |
submitButton.trigger(EVENTS.POST_CREATED, newid);
|
|
|
171 |
hideSubmitButtonLoadingIcon(submitButton);
|
|
|
172 |
allButtons.prop('disabled', false);
|
|
|
173 |
|
|
|
174 |
// Tell formchangechecker we submitted the form.
|
|
|
175 |
FormChangeChecker.resetFormDirtyState(submitButton[0]);
|
|
|
176 |
|
|
|
177 |
return currentRoot.find(Selectors.post.inpageReplyContent).hide();
|
|
|
178 |
})
|
|
|
179 |
.then(function() {
|
|
|
180 |
location.href = "#p" + newid;
|
|
|
181 |
|
|
|
182 |
// Reload the page, say if threshold is being set by user those would get reflected through the templates.
|
|
|
183 |
location.reload();
|
|
|
184 |
})
|
|
|
185 |
.catch(function(error) {
|
|
|
186 |
hideSubmitButtonLoadingIcon(submitButton);
|
|
|
187 |
allButtons.prop('disabled', false);
|
|
|
188 |
return Notification.exception(error);
|
|
|
189 |
});
|
|
|
190 |
}
|
|
|
191 |
});
|
|
|
192 |
|
|
|
193 |
root.on('click', Selectors.post.inpageCancelButton, function(e) {
|
|
|
194 |
// Tell formchangechecker to reset the form state.
|
|
|
195 |
FormChangeChecker.resetFormDirtyState(e.currentTarget);
|
|
|
196 |
});
|
|
|
197 |
};
|
|
|
198 |
|
|
|
199 |
return {
|
|
|
200 |
init: function(root) {
|
|
|
201 |
registerEventListeners(root);
|
|
|
202 |
},
|
|
|
203 |
CONTENT_FORMATS: CONTENT_FORMATS,
|
|
|
204 |
EVENTS: EVENTS
|
|
|
205 |
};
|
|
|
206 |
});
|