MDL-67654 mod_forum: formchangechecker for discussion inline replies.
[moodle.git] / mod / forum / amd / src / inpage_reply.js
CommitLineData
9b4f09ba
P
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/**
902c8f58 17 * This module handles the in page replying to forum posts.
9b4f09ba 18 *
902c8f58 19 * @module mod_forum/inpage_reply
9b4f09ba
P
20 * @package mod_forum
21 * @copyright 2019 Peter Dias
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24define([
25 'jquery',
26 'core/templates',
27 'core/notification',
28 'mod_forum/repository',
29 'mod_forum/selectors',
30 ], function(
31 $,
32 Templates,
33 Notification,
34 Repository,
35 Selectors
36 ) {
37
38 var DISPLAYCONSTANTS = {
2602c7bf 39 NESTED_V2: 4,
9b4f09ba
P
40 THREADED: 2,
41 NESTED: 3,
42 FLAT_OLDEST_FIRST: 1,
43 FLAT_NEWEST_FIRST: -1
44 };
45
7902e4dc
RW
46 var EVENTS = {
47 POST_CREATED: 'mod_forum-post-created'
48 };
49
88f6ca6c
SA
50 /**
51 * Moodle formats taken from the FORMAT_* constants declared in lib/weblib.php.
52 * @type {Object}
53 */
54 var CONTENT_FORMATS = {
55 MOODLE: 0
56 };
902c8f58
RW
57 /**
58 * Show the loading icon for the submit button.
59 *
60 * @param {Object} button The submit button element
61 */
62 var showSubmitButtonLoadingIcon = function(button) {
63 var textContainer = button.find(Selectors.post.inpageSubmitBtnText);
64 var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);
65 var width = button.outerWidth();
66 // Fix the width so that the button size doesn't change when we show the loading icon.
67 button.css('width', width);
68 textContainer.addClass('hidden');
69 loadingIconContainer.removeClass('hidden');
70 };
71
72 /**
73 * Hide the loading icon for the submit button.
74 *
75 * @param {Object} button The submit button element
76 */
77 var hideSubmitButtonLoadingIcon = function(button) {
78 var textContainer = button.find(Selectors.post.inpageSubmitBtnText);
79 var loadingIconContainer = button.find(Selectors.post.loadingIconContainer);
80 // Reset the width back to it's default.
81 button.css('width', '');
82 textContainer.removeClass('hidden');
83 loadingIconContainer.addClass('hidden');
84 };
85
86 /**
87 * Register the event listeners for the submit button of the in page reply.
88 *
89 * @param {Object} root The discussion container element.
90 */
9b4f09ba
P
91 var registerEventListeners = function(root) {
92 root.on('click', Selectors.post.inpageSubmitBtn, function(e) {
93 e.preventDefault();
902c8f58
RW
94 var submitButton = $(e.currentTarget);
95 var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);
96 var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);
a0c9b6af 97 var message = form.elements.post.value.trim();
88f6ca6c
SA
98 // For now, we consider the inline reply post written using the FORMAT_MOODLE (because a textarea is displayed).
99 // In the future, other formats should be supported, letting users to use their preferred editor and format.
100 var messageformat = CONTENT_FORMATS.MOODLE;
101 // The message post will be converted from messageformat to FORMAT_HTML.
117e4bd4 102 var topreferredformat = true;
9b4f09ba
P
103 var postid = form.elements.reply.value;
104 var subject = form.elements.subject.value;
38d96b65 105 var currentRoot = submitButton.closest(Selectors.post.post);
cee572aa 106 var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;
38d96b65
RW
107 var modeSelector = root.find(Selectors.post.modeSelect);
108 var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;
9b4f09ba
P
109 var newid;
110
a0c9b6af 111 if (message.length) {
902c8f58
RW
112 showSubmitButtonLoadingIcon(submitButton);
113 allButtons.prop('disabled', true);
114
117e4bd4 115 Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)
a0c9b6af
P
116 .then(function(context) {
117 var message = context.messages.reduce(function(carry, message) {
118 if (message.type == 'success') {
119 carry += '<p>' + message.message + '</p>';
120 }
121 return carry;
122 }, '');
123 Notification.addNotification({
124 message: message,
125 type: "success"
126 });
9b4f09ba 127
a0c9b6af
P
128 return context;
129 })
130 .then(function(context) {
131 form.reset();
132 var post = context.post;
133 newid = post.id;
38d96b65 134
a0c9b6af 135 switch (mode) {
2602c7bf 136 case DISPLAYCONSTANTS.NESTED_V2:
38d96b65 137 var capabilities = post.capabilities;
1aac58b2
RW
138 var currentAuthorName = currentRoot.children()
139 .not(Selectors.post.repliesContainer)
140 .find(Selectors.post.authorName)
141 .text();
142 post.parentauthorname = currentAuthorName;
143 post.showactionmenu = capabilities.view ||
144 capabilities.controlreadstatus ||
38d96b65
RW
145 capabilities.edit ||
146 capabilities.split ||
147 capabilities.delete ||
148 capabilities.export ||
149 post.urls.viewparent;
2602c7bf 150 return Templates.render('mod_forum/forum_discussion_nested_v2_post_reply', post);
a0c9b6af
P
151 case DISPLAYCONSTANTS.THREADED:
152 return Templates.render('mod_forum/forum_discussion_threaded_post', post);
153 case DISPLAYCONSTANTS.NESTED:
154 return Templates.render('mod_forum/forum_discussion_nested_post', post);
155 default:
156 return Templates.render('mod_forum/forum_discussion_post', post);
157 }
158 })
159 .then(function(html, js) {
38d96b65 160 var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();
a0c9b6af
P
161
162 if (mode == DISPLAYCONSTANTS.FLAT_NEWEST_FIRST) {
163 return Templates.prependNodeContents(repliesnode, html, js);
164 } else {
165 return Templates.appendNodeContents(repliesnode, html, js);
166 }
167 })
168 .then(function() {
7902e4dc 169 submitButton.trigger(EVENTS.POST_CREATED, newid);
902c8f58
RW
170 hideSubmitButtonLoadingIcon(submitButton);
171 allButtons.prop('disabled', false);
f1acce7b
PH
172
173 // Tell formchangechecker we submitted the form.
174 if (typeof M.core_formchangechecker !== 'undefined') {
175 M.core_formchangechecker.reset_form_dirty_state();
176 }
177
a0c9b6af
P
178 return currentRoot.find(Selectors.post.inpageReplyContent).hide();
179 })
180 .then(function() {
181 location.href = "#p" + newid;
182 return;
183 })
902c8f58
RW
184 .catch(function(error) {
185 hideSubmitButtonLoadingIcon(submitButton);
186 allButtons.prop('disabled', false);
187 return Notification.exception(error);
188 });
a0c9b6af 189 }
9b4f09ba
P
190 });
191 };
192
193 return {
194 init: function(root) {
195 registerEventListeners(root);
88f6ca6c 196 },
7902e4dc
RW
197 CONTENT_FORMATS: CONTENT_FORMATS,
198 EVENTS: EVENTS
9b4f09ba
P
199 };
200});