weekly release 4.0dev
[moodle.git] / mod / forum / amd / src / inpage_reply.js
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/>.
16 /**
17  * This module handles the in page replying to forum posts.
18  *
19  * @module     mod_forum/inpage_reply
20  * @package    mod_forum
21  * @copyright  2019 Peter Dias
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
24 define([
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     ) {
38     var DISPLAYCONSTANTS = {
39         NESTED_V2: 4,
40         THREADED: 2,
41         NESTED: 3,
42         FLAT_OLDEST_FIRST: 1,
43         FLAT_NEWEST_FIRST: -1
44     };
46     var EVENTS = {
47         POST_CREATED: 'mod_forum-post-created'
48     };
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     };
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     };
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     };
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      */
91     var registerEventListeners = function(root) {
92         root.on('click', Selectors.post.inpageSubmitBtn, function(e) {
93             e.preventDefault();
94             var submitButton = $(e.currentTarget);
95             var allButtons = submitButton.parent().find(Selectors.post.inpageReplyButton);
96             var form = submitButton.parents(Selectors.post.inpageReplyForm).get(0);
97             var message = form.elements.post.value.trim();
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.
102             var topreferredformat = true;
103             var postid = form.elements.reply.value;
104             var subject = form.elements.subject.value;
105             var currentRoot = submitButton.closest(Selectors.post.post);
106             var isprivatereply = form.elements.privatereply != undefined ? form.elements.privatereply.checked : false;
107             var modeSelector = root.find(Selectors.post.modeSelect);
108             var mode = modeSelector.length ? parseInt(modeSelector.get(0).value) : null;
109             var newid;
111             if (message.length) {
112                 showSubmitButtonLoadingIcon(submitButton);
113                 allButtons.prop('disabled', true);
115                 Repository.addDiscussionPost(postid, subject, message, messageformat, isprivatereply, topreferredformat)
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                         });
128                         return context;
129                     })
130                     .then(function(context) {
131                         form.reset();
132                         var post = context.post;
133                         newid = post.id;
135                         switch (mode) {
136                             case DISPLAYCONSTANTS.NESTED_V2:
137                                 var capabilities = post.capabilities;
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 ||
145                                                       capabilities.edit ||
146                                                       capabilities.split ||
147                                                       capabilities.delete ||
148                                                       capabilities.export ||
149                                                       post.urls.viewparent;
150                                 return Templates.render('mod_forum/forum_discussion_nested_v2_post_reply', post);
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) {
160                         var repliesnode = currentRoot.find(Selectors.post.repliesContainer).first();
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() {
169                         submitButton.trigger(EVENTS.POST_CREATED, newid);
170                         hideSubmitButtonLoadingIcon(submitButton);
171                         allButtons.prop('disabled', false);
173                         // Tell formchangechecker we submitted the form.
174                         if (typeof M.core_formchangechecker !== 'undefined') {
175                             M.core_formchangechecker.reset_form_dirty_state();
176                         }
178                         return currentRoot.find(Selectors.post.inpageReplyContent).hide();
179                     })
180                     .then(function() {
181                         location.href = "#p" + newid;
182                         return;
183                     })
184                     .catch(function(error) {
185                         hideSubmitButtonLoadingIcon(submitButton);
186                         allButtons.prop('disabled', false);
187                         return Notification.exception(error);
188                     });
189             }
190         });
191     };
193     return {
194         init: function(root) {
195             registerEventListeners(root);
196         },
197         CONTENT_FORMATS: CONTENT_FORMATS,
198         EVENTS: EVENTS
199     };
200 });