MDL-63915 core_message: removed unused AMD modules

This commit is contained in:
Mark Nelson 2018-12-03 13:35:13 +08:00
parent b01d0535bc
commit 273dadeb50
18 changed files with 0 additions and 2841 deletions

View File

@ -1 +0,0 @@
define(["jquery","core_message/message_area_contacts","core_message/message_area_messages","core_message/message_area_profile","core_message/message_area_tabs","core_message/message_area_search"],function(a,b,c,d,e,f){function g(b,c,d,e){this.node=a(b),this.pollmin=c,this.pollmax=d,this.polltimeout=e,this._init()}return g.prototype.node=null,g.prototype.pollmin=null,g.prototype.pollmax=null,g.prototype.polltimeout=null,g.prototype._init=function(){new b(this),new c(this),new d(this),new e(this),new f(this)},g.prototype.onDelegateEvent=function(a,b,c){this.node.on(a,b,c)},g.prototype.onCustomEvent=function(a,b){this.node.on(a,b)},g.prototype.trigger=function(a,b){"undefined"==typeof b&&(b=""),this.node.trigger(a,b)},g.prototype.find=function(a){return this.node.find(a)},g.prototype.getCurrentUserId=function(){return this.node.data("userid")},g.prototype.showContactsFirst=function(){return!!this.node.data("displaycontacts")},g});

View File

@ -1 +0,0 @@
define(["core_message/message_area_events"],function(a){function b(a){this.messageArea=a}var c={MESSAGES:"[data-region='messages']"};return b.prototype.messageArea=null,b.prototype.chooseMessagesToDelete=function(){0!==this.messageArea.find(c.MESSAGES).length&&this.messageArea.trigger(a.CHOOSEMESSAGESTODELETE)},b});

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define([],function(){return{CANCELDELETEMESSAGES:"cancel-delete-messages",CHOOSEMESSAGESTODELETE:"choose-messages-to-delete",CONTACTADDED:"contact-added",CONTACTBLOCKED:"contact-blocked",CONTACTREMOVED:"contact-removed",CONTACTSELECTED:"contact-selected",CONTACTSSELECTED:"contacts-selected",CONTACTUNBLOCKED:"contact-unblocked",CONVERSATIONDELETED:"conversation-deleted",CONVERSATIONSELECTED:"conversation-selected",CONVERSATIONSSELECTED:"conversations-selected",MESSAGESDELETED:"messages-deleted",MESSAGESEARCHCANCELED:"message-search-canceled",MESSAGESENT:"message-sent",SENDMESSAGE:"message-send",USERSSEARCHCANCELED:"users-search-canceled"}});

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define(["jquery","core/ajax","core/templates","core/notification","core/str","core/config","core/custom_interaction_events","core_message/message_area_events"],function(a,b,c,d,e,f,g,h){function i(a){this.messageArea=a,this._init()}var j={PROFILE:"[data-region='profile']",PROFILEADDCONTACT:"[data-action='profile-add-contact']",PROFILEBLOCKCONTACT:"[data-action='profile-block-contact']",PROFILEREMOVECONTACT:"[data-action='profile-remove-contact']",PROFILESENDMESSAGE:"[data-action='profile-send-message']",PROFILEUNBLOCKCONTACT:"[data-action='profile-unblock-contact']",PROFILEVIEW:"[data-action='profile-view']",SHOWCONTACTS:"[data-action='show-contacts']",MESSAGESAREA:"[data-region='messages-area']",MESSAGINGAREA:"[data-region='messaging-area']"};return i.prototype.messageArea=null,i.prototype._init=function(){g.define(this.messageArea.node,[g.events.activate]),this.messageArea.onCustomEvent(h.CONTACTSELECTED,this._viewProfile.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILEVIEW,function(a,b){this._viewFullProfile(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILESENDMESSAGE,function(a,b){this._sendMessage(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILEUNBLOCKCONTACT,function(a,b){this._unblockContact(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILEBLOCKCONTACT,function(a,b){this._blockContact(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILEADDCONTACT,function(a,b){this._addContact(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.PROFILEREMOVECONTACT,function(a,b){this._removeContact(),b.originalEvent.preventDefault()}.bind(this)),this.messageArea.onDelegateEvent(g.events.activate,j.SHOWCONTACTS,this._hideMessagingArea.bind(this))},i.prototype._viewProfile=function(a,e){c.render("core/loading",{}).done(function(a,b){c.replaceNodeContents(this.messageArea.find(j.MESSAGESAREA),a,b)}.bind(this));var f=b.call([{methodname:"core_message_data_for_messagearea_get_profile",args:{currentuserid:this.messageArea.getCurrentUserId(),otheruserid:e}}]);return f[0].then(function(a){return c.render("core_message/message_area_profile",a)}).then(function(a,b){c.replaceNodeContents(this.messageArea.find(j.MESSAGESAREA),a,b)}.bind(this)).fail(d.exception)},i.prototype._viewFullProfile=function(){window.location.href=f.wwwroot+"/user/profile.php?id="+this._getUserId()},i.prototype._sendMessage=function(){this.messageArea.trigger(h.SENDMESSAGE,this._getUserId())},i.prototype._blockContact=function(){var a=this._performAction("core_message_block_user","unblockcontact","profile-block-contact","profile-unblock-contact","");return a.then(function(){this.messageArea.trigger(h.CONTACTBLOCKED,this._getUserId())}.bind(this))},i.prototype._unblockContact=function(){var a=this._performAction("core_message_unblock_user","blockcontact","profile-unblock-contact","profile-block-contact","danger");return a.then(function(){this.messageArea.trigger(h.CONTACTUNBLOCKED,this._getUserId())}.bind(this))},i.prototype._addContact=function(){var a=this._performAction("core_message_create_contact_request","removecontact","profile-add-contact","profile-remove-contact","danger");return a.then(function(){this.messageArea.trigger(h.CONTACTADDED,this._getUserId())}.bind(this))},i.prototype._removeContact=function(){var a=this._performAction("core_message_delete_contacts","addcontact","profile-remove-contact","profile-add-contact","");return a.then(function(){this.messageArea.trigger(h.CONTACTREMOVED,this._getUserId())}.bind(this))},i.prototype._performAction=function(a,c,f,g,h){var i="";switch(a){case"core_message_block_user":i={userid:this.messageArea.getCurrentUserId(),blockeduserid:this._getUserId()};break;case"core_message_unblock_user":i={userid:this.messageArea.getCurrentUserId(),unblockeduserid:this._getUserId()};break;case"core_message_create_contact_request":i={userid:this.messageArea.getCurrentUserId(),requesteduserid:this._getUserId()};break;default:i={userid:this.messageArea.getCurrentUserId(),userids:[this._getUserId()]}}var j=b.call([{methodname:a,args:i}]);return j[0].then(function(){return e.get_string(c,"message")}).then(function(a){this._changeText(a,f,g,h)}.bind(this)).fail(d.exception)},i.prototype._changeText=function(a,b,c,d){var e=this.messageArea.find("[data-action='"+b+"']");e.text(a),e.removeClass(),d&&e.addClass(d),e.attr("data-action",c)},i.prototype._getUserId=function(){return this.messageArea.find(j.PROFILE).data("userid")},i.prototype._hideMessagingArea=function(){this.messageArea.find(j.MESSAGINGAREA).removeClass("show-messages").addClass("hide-messages")},i});

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define(["core/custom_interaction_events","core_message/message_area_events"],function(a,b){function c(a){this.messageArea=a,this._init()}var d={ACTIVECONTACTSTAB:"[data-region='contacts-area'] [role='tab'][aria-selected='true']",CONTACTSPANELS:"[data-region='contacts']",VIEWCONTACTS:"[data-action='contacts-view']",VIEWCONVERSATIONS:"[data-action='conversations-view']"};return c.prototype.messageArea=null,c.prototype._init=function(){a.define(this.messageArea.node,[a.events.activate,a.events.up,a.events.down,a.events.next,a.events.previous,a.events.ctrlPageUp,a.events.ctrlPageDown]),this.messageArea.onDelegateEvent(a.events.activate,d.VIEWCONVERSATIONS,this._viewConversations.bind(this)),this.messageArea.onDelegateEvent(a.events.activate,d.VIEWCONTACTS,this._viewContacts.bind(this)),this.messageArea.onDelegateEvent(a.events.up,d.VIEWCONVERSATIONS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.down,d.VIEWCONVERSATIONS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.next,d.VIEWCONVERSATIONS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.previous,d.VIEWCONVERSATIONS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.up,d.VIEWCONTACTS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.down,d.VIEWCONTACTS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.next,d.VIEWCONTACTS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.previous,d.VIEWCONTACTS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.ctrlPageUp,d.CONTACTSPANELS,this._toggleTabs.bind(this)),this.messageArea.onDelegateEvent(a.events.ctrlPageDown,d.CONTACTSPANELS,this._toggleTabs.bind(this)),this.messageArea.onCustomEvent(b.MESSAGESENT,function(){this._selectTab(d.VIEWCONVERSATIONS,d.VIEWCONTACTS)}.bind(this))},c.prototype._viewConversations=function(){this.messageArea.trigger(b.CONVERSATIONSSELECTED),this._selectTab(d.VIEWCONVERSATIONS,d.VIEWCONTACTS)},c.prototype._viewContacts=function(){this.messageArea.trigger(b.CONTACTSSELECTED),this._selectTab(d.VIEWCONTACTS,d.VIEWCONVERSATIONS)},c.prototype._selectTab=function(a,b){b=this.messageArea.find(b),b.removeClass("selected"),b.attr("aria-selected","false"),b.attr("tabindex","-1"),a=this.messageArea.find(a),a.addClass("selected"),a.attr("aria-selected","true"),a.attr("tabindex","0")},c.prototype._toggleTabs=function(a,b){var c=this.messageArea.find(d.ACTIVECONTACTSTAB);c.is(d.VIEWCONVERSATIONS)?this._viewContacts():this._viewConversations(),this.messageArea.find(d.ACTIVECONTACTSTAB).focus(),a.preventDefault(),a.stopPropagation(),b.originalEvent.preventDefault(),b.originalEvent.stopPropagation()},c});

View File

@ -1 +0,0 @@
define(["jquery","core/ajax","core/notification","core_message/message_notification_preference","core/custom_interaction_events"],function(a,b,c,d,e){var f={PREFERENCE:"[data-state]",PREFERENCES_CONTAINER:'[data-region="preferences-container"]',CONTACTABLE_PRIVACY_CONTAINER:'[data-region="privacy-setting-container"]'},g=function(b){this.root=a(b),this.userId=this.root.find(f.PREFERENCES_CONTAINER).attr("data-user-id"),this.registerEventListeners()};return g.prototype.preferencesDisabled=function(){return this.root.find(f.PREFERENCES_CONTAINER).hasClass("disabled")},g.prototype.saveContactablePrivacySetting=function(){var d=this.root.find(f.CONTACTABLE_PRIVACY_CONTAINER),e=a("input[type='radio']:checked").val();if(d.hasClass("loading"))return a.Deferred().resolve();d.addClass("loading");var g={methodname:"core_user_update_user_preferences",args:{userid:this.userId,preferences:[{type:d.attr("data-preference-key"),value:e}]}};return b.call([g])[0].fail(c.exception).always(function(){d.removeClass("loading")})},g.prototype.registerEventListeners=function(){e.define(this.root,[e.events.activate]),this.root.on("change",function(b){if("message_blocknoncontacts"==b.target.name)this.saveContactablePrivacySetting();else if(!this.preferencesDisabled()){var c=a(b.target).closest(f.PREFERENCES_CONTAINER),e=a(b.target).closest(f.PREFERENCE),g=new d(c,this.userId);e.addClass("loading"),g.save().always(function(){e.removeClass("loading")})}}.bind(this))},g});

View File

@ -1,131 +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/>.
/**
* This module instantiates the functionality of the messaging area.
*
* @module core_message/message_area
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core_message/message_area_contacts', 'core_message/message_area_messages',
'core_message/message_area_profile', 'core_message/message_area_tabs', 'core_message/message_area_search'],
function($, Contacts, Messages, Profile, Tabs, Search) {
/**
* Messagearea class.
*
* @param {String} selector The selector for the page region containing the message area.
* @param {int} pollmin
* @param {int} pollmax
* @param {int} polltimeout
*/
function Messagearea(selector, pollmin, pollmax, polltimeout) {
this.node = $(selector);
this.pollmin = pollmin;
this.pollmax = pollmax;
this.polltimeout = polltimeout;
this._init();
}
/** @type {jQuery} The jQuery node for the page region containing the message area. */
Messagearea.prototype.node = null;
/** @type {int} The minimum time to poll for messages. */
Messagearea.prototype.pollmin = null;
/** @type {int} The maximum time to poll for messages. */
Messagearea.prototype.pollmax = null;
/** @type {int} The time used once we have reached the maximum polling time. */
Messagearea.prototype.polltimeout = null;
/**
* Initialise the other objects we require.
*/
Messagearea.prototype._init = function() {
new Contacts(this);
new Messages(this);
new Profile(this);
new Tabs(this);
new Search(this);
};
/**
* Handles adding a delegate event to the messaging area node.
*
* @param {String} action The action we are listening for
* @param {String} selector The selector for the page we are assigning the action to
* @param {Function} callable The function to call when the event happens
*/
Messagearea.prototype.onDelegateEvent = function(action, selector, callable) {
this.node.on(action, selector, callable);
};
/**
* Handles adding a custom event to the messaging area node.
*
* @param {String} action The action we are listening for
* @param {Function} callable The function to call when the event happens
*/
Messagearea.prototype.onCustomEvent = function(action, callable) {
this.node.on(action, callable);
};
/**
* Handles triggering an event on the messaging area node.
*
* @param {String} event The selector for the page region containing the message area
* @param {Object=} data The data to pass when we trigger the event
*/
Messagearea.prototype.trigger = function(event, data) {
if (typeof data == 'undefined') {
data = '';
}
this.node.trigger(event, data);
};
/**
* Handles finding a node in the messaging area.
*
* @param {String} selector The selector for the node we are looking for
* @return {jQuery} The node
*/
Messagearea.prototype.find = function(selector) {
return this.node.find(selector);
};
/**
* Returns the ID of the user whose message area we are viewing.
*
* @return {int} The user id
*/
Messagearea.prototype.getCurrentUserId = function() {
return this.node.data('userid');
};
/**
* Function to determine if we should be showing contacts initially or messages.
*
* @return {boolean} True to show contacts first, otherwise show messages.
*/
Messagearea.prototype.showContactsFirst = function() {
return !!this.node.data('displaycontacts');
};
return Messagearea;
}
);

View File

@ -1,54 +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/>.
/**
* The module handles any actions we perform on the message area.
*
* @module core_message/message_area_actions
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core_message/message_area_events'], function(Events) {
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
MESSAGES: "[data-region='messages']"
};
/**
* Actions class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Actions(messageArea) {
this.messageArea = messageArea;
}
/** @type {Messagearea} The messaging area object. */
Actions.prototype.messageArea = null;
/**
* Handles when we have selected to delete messages.
*/
Actions.prototype.chooseMessagesToDelete = function() {
// Only fire the event if we are viewing messages.
if (this.messageArea.find(SELECTORS.MESSAGES).length !== 0) {
this.messageArea.trigger(Events.CHOOSEMESSAGESTODELETE);
}
};
return Actions;
});

View File

@ -1,711 +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/>.
/**
* This module handles the contacts area of the messaging area.
*
* @module core_message/message_area_contacts
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/custom_interaction_events', 'core/str',
'core_message/message_area_events'],
function($, Ajax, Templates, Notification, CustomEvents, Str, Events) {
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
CONTACT: "[data-region='contact']",
CONTACTICONBLOCKED: "[data-region='contact-icon-blocked']",
CONTACTS: "[data-region='contacts'][data-region-content='contacts']",
CONTACTSAREA: "[data-region='contacts-area']",
CONVERSATIONS: "[data-region='contacts'][data-region-content='conversations']",
COURSE: "[data-region='course']",
LASTMESSAGETEXT: "[data-region='last-message-text']",
LASTMESSAGEUSER: "[data-region='last-message-user']",
LOADINGICON: '.loading-icon',
MESSAGETEXT: "[data-region='message-text']",
MESSAGINGAREA: "[data-region='messaging-area']",
NOCONTACTS: "[data-region=no-contacts]",
SEARCHBOX: "[data-region='search-box']",
SEARCHRESULTSAREA: "[data-region='search-results-area']",
SEARCHTEXTAREA: "[data-region='search-text-area']",
SELECTEDVIEWCONVERSATION: "[data-action='view-contact-msg'].selected",
SELECTEDVIEWPROFILE: "[data-action='view-contact-profile'].selected",
SHOWMESSAGES: "[data-action='show-messages']",
VIEWCONVERSATION: "[data-action='view-contact-msg']",
VIEWPROFILE: "[data-action='view-contact-profile']"
};
/**
* Contacts class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Contacts(messageArea) {
this.messageArea = messageArea;
this._init();
}
/** @type {Boolean} checks if we are currently loading conversations */
Contacts.prototype._isLoadingConversations = false;
/** @type {Boolean} checks if we are currently loading contacts */
Contacts.prototype._isLoadingContacts = false;
/** @type {int} the number of contacts displayed */
Contacts.prototype._numContactsDisplayed = 0;
/** @type {int} the number of contacts to retrieve */
Contacts.prototype._numContactsToRetrieve = 20;
/** @type {int} the number of conversations displayed */
Contacts.prototype._numConversationsDisplayed = 0;
/** @type {int} the number of conversations to retrieve */
Contacts.prototype._numConversationsToRetrieve = 20;
/** @type {int} the number of chars of the message to show */
Contacts.prototype._messageLength = 60;
/** @type {Messagearea} The messaging area object. */
Contacts.prototype.messageArea = null;
/**
* Initialise the event listeners.
*
* @private
*/
Contacts.prototype._init = function() {
CustomEvents.define(this.messageArea.node, [
CustomEvents.events.activate,
CustomEvents.events.down,
CustomEvents.events.up,
]);
this.messageArea.onCustomEvent(Events.MESSAGESEARCHCANCELED, this._viewConversations.bind(this));
this.messageArea.onCustomEvent(Events.USERSSEARCHCANCELED, this._viewContacts.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTSSELECTED, this._viewContacts.bind(this));
this.messageArea.onCustomEvent(Events.CONVERSATIONDELETED, this._deleteConversation.bind(this));
this.messageArea.onCustomEvent(Events.CONVERSATIONSSELECTED, this._viewConversations.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTSSELECTED, this._viewContacts.bind(this));
this.messageArea.onCustomEvent(Events.MESSAGESDELETED, this._updateLastMessage.bind(this));
this.messageArea.onCustomEvent(Events.MESSAGESENT, this._handleMessageSent.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTREMOVED, function(e, userid) {
this._removeContact(SELECTORS.CONTACTS, userid);
}.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTADDED, function(e, userid) {
this._addContact(userid);
}.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTBLOCKED, function(e, userid) {
this._blockContact(userid);
}.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTUNBLOCKED, function(e, userid) {
this._unblockContact(userid);
}.bind(this));
this.messageArea.onCustomEvent(Events.CHOOSEMESSAGESTODELETE,
this._startDeleting.bind(this));
this.messageArea.onCustomEvent(Events.CANCELDELETEMESSAGES,
this._stopDeleting.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.VIEWCONVERSATION,
this._viewConversation.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.VIEWPROFILE,
this._viewContact.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SHOWMESSAGES,
this._showMessagingArea.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.CONTACT,
this._selectPreviousContact.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.CONTACT,
this._selectNextContact.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.VIEWCONVERSATION,
this._selectPreviousConversation.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.VIEWCONVERSATION,
this._selectNextConversation.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.COURSE, this._selectPreviousCourse.bind());
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.COURSE, this._selectNextCourse.bind());
this.messageArea.onDelegateEvent('focus', SELECTORS.SEARCHBOX, this._setSearching.bind(this));
this.messageArea.onDelegateEvent('blur', SELECTORS.SEARCHBOX, this._clearSearching.bind(this));
// Now enable the ability to infinitely scroll through conversations and contacts.
CustomEvents.define(this.messageArea.find(SELECTORS.CONVERSATIONS), [
CustomEvents.events.scrollBottom
]);
CustomEvents.define(this.messageArea.find(SELECTORS.CONTACTS), [
CustomEvents.events.scrollBottom
]);
this.messageArea.onDelegateEvent(CustomEvents.events.scrollBottom, SELECTORS.CONVERSATIONS,
this._loadConversations.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.scrollBottom, SELECTORS.CONTACTS,
this._loadContacts.bind(this));
if (!this.messageArea.showContactsFirst()) {
// Set the initial number of conversations to retrieve. Otherwise it will display no conversations.
this._numConversationsDisplayed = 20;
}
};
/**
* Turn on deleting.
*
* @private
*/
Contacts.prototype._startDeleting = function() {
this.messageArea.find(SELECTORS.CONTACTSAREA).addClass('editing');
};
/**
* Turn off deleting.
*
* @private
*/
Contacts.prototype._stopDeleting = function() {
this.messageArea.find(SELECTORS.CONTACTSAREA).removeClass('editing');
};
/**
* Handles viewing the list of conversations.
*
* @private
*/
Contacts.prototype._viewConversations = function() {
// If conversations is empty then try load some.
if (this._numConversationsDisplayed === 0) {
this._loadConversations();
}
this.messageArea.find(SELECTORS.CONTACTS).hide();
this.messageArea.find(SELECTORS.CONVERSATIONS).show();
};
/**
* Handles viewing the list of contacts.
*
* @private
*/
Contacts.prototype._viewContacts = function() {
// If contacts is empty then try load some.
if (this._numContactsDisplayed === 0) {
this._loadContacts();
}
this.messageArea.find(SELECTORS.CONVERSATIONS).hide();
this.messageArea.find(SELECTORS.CONTACTS).show();
};
/**
* Handles when a message is sent.
*
* @param {Event} event The message sent event
* @param {int} userid The id of the user who the message was sent to
* @param {String} text The message text
* @private
*/
Contacts.prototype._handleMessageSent = function(event, userid, text) {
// Switch to viewing the conversations.
this._viewConversations();
// Get the user node.
var user = this._getUserNode(SELECTORS.CONVERSATIONS, userid);
// If the user has not been loaded yet, let's copy the element from contact or search panel to the conversation panel.
if (user.length === 0) {
// Let's clone the data on the contact page.
var usercontact = this._getUserNode(SELECTORS.CONTACTS, userid);
if (usercontact.length === 0) {
// No luck, maybe we sent the message to a user we searched for - check search page.
usercontact = this._getUserNode(SELECTORS.SEARCHRESULTSAREA, userid);
}
if (usercontact.length == 0) {
// Can't do much.
return;
}
user = usercontact.clone();
// Change the data action attribute.
user.attr('data-action', 'view-contact-msg');
// Remove the 'no conversations' message.
this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
SELECTORS.NOCONTACTS).remove();
// Increment the number of conversations displayed.
this._numConversationsDisplayed++;
}
// Move the contact to the top of the list.
user.prependTo(this.messageArea.find(SELECTORS.CONVERSATIONS));
// Scroll to the top.
this.messageArea.find(SELECTORS.CONVERSATIONS).scrollTop(0);
// Get the new text to show.
this._updateContactText(user, text, true);
// Ensure user is selected.
this._setSelectedUser("[data-userid='" + userid + "']");
};
/**
* Handles loading conversations.
*
* @return {Promise|boolean} The promise resolved when the contact area has been rendered,
* @private
*/
Contacts.prototype._loadConversations = function() {
if (this._isLoadingConversations) {
return false;
}
// Tell the user we are loading items.
this._isLoadingConversations = true;
// Keep track of the number of contacts
var numberreceived = 0;
// Add loading icon to the end of the list.
return Templates.render('core/loading', {}).then(function(html, js) {
if (this._numConversationsDisplayed) {
Templates.appendNodeContents(this.messageArea.find(SELECTORS.CONVERSATIONS),
"<div style='text-align:center'>" + html + "</div>", js);
} else { // No conversations, just replace contents.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.CONVERSATIONS),
"<div style='text-align:center'>" + html + "</div>", js);
}
return this._getItems('core_message_data_for_messagearea_conversations',
this._numConversationsDisplayed, this._numConversationsToRetrieve);
}.bind(this)).then(function(data) {
numberreceived = data.contacts.length;
data.isconversation = true;
return Templates.render('core_message/message_area_contacts', data);
}).then(function(html, js) {
// Remove the loading icon.
this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
SELECTORS.LOADINGICON).remove();
// Only append data if we got data back.
if (numberreceived > 0) {
// Show the new content.
Templates.appendNodeContents(this.messageArea.find(SELECTORS.CONVERSATIONS), html, js);
// Increment the number of conversations displayed. We increment by the number of conversations we
// asked to retrieve not by the number that was actually retrieved, see MDL-55870.
this._numConversationsDisplayed += this._numConversationsToRetrieve;
} else if (!this._numConversationsDisplayed) {
// If we didn't receive any contacts and there are currently none, then we want to show a message.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.CONVERSATIONS), html, js);
}
// Mark that we are no longer busy loading data.
this._isLoadingConversations = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Handles loading contacts.
*
* @return {Promise|boolean} The promise resolved when the contact area has been rendered
* @private
*/
Contacts.prototype._loadContacts = function() {
if (this._isLoadingContacts) {
return false;
}
// Tell the user we are loading items.
this._isLoadingContacts = true;
// Keep track of the number of contacts
var numberreceived = 0;
// Add loading icon to the end of the list.
return Templates.render('core/loading', {}).then(function(html, js) {
if (this._numContactsDisplayed) {
Templates.appendNodeContents(this.messageArea.find(SELECTORS.CONTACTS),
"<div style='text-align:center'>" + html + "</div>", js);
} else { // No contacts, just replace contents.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.CONTACTS),
"<div style='text-align:center'>" + html + "</div>", js);
}
return this._getItems('core_message_data_for_messagearea_contacts',
this._numContactsDisplayed, this._numContactsToRetrieve);
}.bind(this)).then(function(data) {
numberreceived = data.contacts.length;
data.isconversation = false;
return Templates.render('core_message/message_area_contacts', data);
}).then(function(html, js) {
// Remove the loading icon.
this.messageArea.find(SELECTORS.CONTACTS + " " +
SELECTORS.LOADINGICON).remove();
// Only append data if we got data back.
if (numberreceived > 0) {
// Show the new content.
Templates.appendNodeContents(this.messageArea.find(SELECTORS.CONTACTS), html, js);
// Increment the number of contacts displayed.
this._numContactsDisplayed += numberreceived;
} else if (!this._numContactsDisplayed) {
// If we didn't receive any contacts and there are currently none, then we want to show a message.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.CONTACTS), html, js);
}
// Mark that we are no longer busy loading data.
this._isLoadingContacts = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Handles viewing a particular conversation.
*
* @param {Event} event
* @private
*/
Contacts.prototype._viewConversation = function(event) {
// Cancel any deletion of messages we may have.
this.messageArea.trigger(Events.CANCELDELETEMESSAGES);
var userid = $(event.currentTarget).data('userid');
var messageid = $(event.currentTarget).data('messageid');
var selector = "[data-userid='" + userid + "']";
// If we have a specific message id then we did a search and the contact may appear in multiple
// places - we don't want to highlight them all.
if (messageid) {
selector = "[data-messageid='" + messageid + "']";
}
this._setSelectedUser(selector);
this.messageArea.trigger(Events.CONVERSATIONSELECTED, userid);
// Don't highlight the contact because the message region has changed.
this.messageArea.find(SELECTORS.SELECTEDVIEWPROFILE).removeClass('selected');
this._showMessagingArea();
};
/**
* Handles viewing a particular contact.
*
* @param {Event} event
* @private
*/
Contacts.prototype._viewContact = function(event) {
// Cancel any deletion of messages we may have.
this.messageArea.trigger(Events.CANCELDELETEMESSAGES);
var userid = $(event.currentTarget).data('userid');
this._setSelectedUser("[data-userid='" + userid + "']");
this.messageArea.trigger(Events.CONTACTSELECTED, userid);
// Don't highlight the conversation because the message region has changed.
this.messageArea.find(SELECTORS.SELECTEDVIEWCONVERSATION).removeClass('selected');
this._showMessagingArea();
};
/**
* Handles returning a list of items to display.
*
* @param {String} webservice The web service to call
* @param {int} limitfrom
* @param {int} limitnum
* @return {Promise} The promise resolved when the contact area has been rendered
* @private
*/
Contacts.prototype._getItems = function(webservice, limitfrom, limitnum) {
// Call the web service to return the data we want to view.
var promises = Ajax.call([{
methodname: webservice,
args: {
userid: this.messageArea.getCurrentUserId(),
limitfrom: limitfrom,
limitnum: limitnum
}
}]);
return promises[0];
};
/**
* Handles deleting a conversation.
*
* @param {Event} event
* @param {int} userid The user id belonging to the messages we are deleting.
* @private
*/
Contacts.prototype._deleteConversation = function(event, userid) {
// Remove the conversation.
this._removeContact(SELECTORS.CONVERSATIONS, userid);
this._numConversationsDisplayed--;
this._hideMessagingArea();
// Now we have done all the deletion we can set the flag back to false.
this._stopDeleting();
};
/**
* Handles updating the last message in the contact.
*
* @param {Event} event
* @param {int} userid The user id belonging to the messages we are deleting
* @param {jQuery|null} updatemessage The message we need to update the contact panel with
* @private
*/
Contacts.prototype._updateLastMessage = function(event, userid, updatemessage) {
// Check if the last message needs updating.
if (updatemessage) {
var user = this._getUserNode(SELECTORS.CONVERSATIONS, userid);
var updatemessagetext = updatemessage.find(SELECTORS.MESSAGETEXT).text().trim();
var sentbyuser = false;
if (updatemessage.data('useridto') == userid) {
// Must have been sent by the currently logged in user.
sentbyuser = true;
}
this._updateContactText(user, updatemessagetext, sentbyuser);
}
// Now we have done all the deletion we can set the flag back to false.
this._stopDeleting();
};
/**
* Handles adding a contact to the list.
*
* @private
*/
Contacts.prototype._addContact = function() {
this.messageArea.find(SELECTORS.CONTACTS).empty();
this._numContactsDisplayed = 0;
this._loadContacts();
};
/**
* Handles removing a contact from the list.
*
* @param {String} selector
* @param {int} userid
* @private
*/
Contacts.prototype._removeContact = function(selector, userid) {
this._getUserNode(selector, userid).remove();
this._numContactsDisplayed--;
};
/**
* Handles marking a contact as blocked on the list.
*
* @param {int} userid
* @private
*/
Contacts.prototype._blockContact = function(userid) {
var user = this._getUserNode(SELECTORS.CONTACTS, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).removeClass('hidden');
user = this._getUserNode(SELECTORS.CONVERSATIONS, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).removeClass('hidden');
user = this._getUserNode(SELECTORS.SEARCHRESULTSAREA, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).removeClass('hidden');
};
/**
* Handles marking a contact as unblocked on the list.
*
* @param {int} userid
* @private
*/
Contacts.prototype._unblockContact = function(userid) {
var user = this._getUserNode(SELECTORS.CONTACTS, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).addClass('hidden');
user = this._getUserNode(SELECTORS.CONVERSATIONS, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).addClass('hidden');
user = this._getUserNode(SELECTORS.SEARCHRESULTSAREA, userid);
user.find(SELECTORS.CONTACTICONBLOCKED).addClass('hidden');
};
/**
* Handles retrieving a user node from a list.
*
* @param {String} selector
* @param {int} userid
* @return {jQuery} The user node
* @private
*/
Contacts.prototype._getUserNode = function(selector, userid) {
return this.messageArea.find(selector + " " + SELECTORS.CONTACT +
"[data-userid='" + userid + "']");
};
/**
* Handles selecting a contact in the list.
*
* @param {String} selector
* @private
*/
Contacts.prototype._setSelectedUser = function(selector) {
// Remove the 'selected' class from any other contact.
this.messageArea.find(SELECTORS.CONTACT).removeClass('selected');
this.messageArea.find(SELECTORS.CONTACT).attr('aria-pressed', false);
// Set the tab for the user to selected.
this.messageArea.find(SELECTORS.CONTACT + selector).addClass('selected');
this.messageArea.find(SELECTORS.CONTACT + selector).attr('aria-pressed', true);
};
/**
* Converts a text message into the text that should be stored in the contact list
*
* @param {String} text
* @return {String} The altered text
*/
Contacts.prototype._getContactText = function(text) {
if (text.length > this._messageLength) {
text = text.substr(0, this._messageLength - 3);
text += '...';
}
// Text node prevents script injection through HTML entities.
return document.createTextNode(text);
};
/**
* Handles updating the contact text.
*
* @param {jQuery} user The user to update
* @param {String} text The text to update the contact with
* @param {Boolean} sentbyuser Was it sent by the currently logged in user?
* @private
*/
Contacts.prototype._updateContactText = function(user, text, sentbyuser) {
// Get the text we will display on the contact panel.
text = this._getContactText(text);
if (sentbyuser) {
Str.get_string('you', 'message').done(function(string) {
// Ensure we display that the message is from this user.
user.find(SELECTORS.LASTMESSAGEUSER).empty().append(string);
}).always(function() {
user.find(SELECTORS.LASTMESSAGETEXT).empty().append(text);
});
} else {
user.find(SELECTORS.LASTMESSAGEUSER).empty();
user.find(SELECTORS.LASTMESSAGETEXT).empty().append(text);
}
};
/**
* Shifts focus to the next contact in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectNextContact = function(e, data) {
var contact = $(e.target).closest(SELECTORS.CONTACT);
var next = contact.next();
next.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Shifts focus to the previous contact in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectPreviousContact = function(e, data) {
var contact = $(e.target).closest(SELECTORS.CONTACT);
var previous = contact.prev();
previous.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Shifts focus to the next course in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectNextCourse = function(e, data) {
var course = $(e.target).closest(SELECTORS.COURSE);
course.next().focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Shifts focus to the previous course in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectPreviousCourse = function(e, data) {
var course = $(e.target).closest(SELECTORS.COURSE);
course.prev().focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Shifts focus to the next conversation in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectNextConversation = function(e, data) {
var conversation = $(e.target).closest(SELECTORS.VIEWCONVERSATION);
var next = conversation.next();
next.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Shifts focus to the previous conversation in the list.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
*/
Contacts.prototype._selectPreviousConversation = function(e, data) {
var conversation = $(e.target).closest(SELECTORS.VIEWCONVERSATION);
var previous = conversation.prev();
previous.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Flags the search area as seaching.
*/
Contacts.prototype._setSearching = function() {
$(SELECTORS.SEARCHTEXTAREA).addClass('searching');
};
/**
* Flags the search area as seaching.
*/
Contacts.prototype._clearSearching = function() {
$(SELECTORS.SEARCHTEXTAREA).removeClass('searching');
};
/**
* Make the messaging area visible.
*/
Contacts.prototype._showMessagingArea = function() {
this.messageArea.find(SELECTORS.MESSAGINGAREA)
.removeClass('hide-messages')
.addClass('show-messages');
};
/**
* Hide the messaging area.
*/
Contacts.prototype._hideMessagingArea = function() {
this.messageArea.find(SELECTORS.MESSAGINGAREA)
.removeClass('show-messages')
.addClass('hide-messages');
};
return Contacts;
}
);

View File

@ -1,45 +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/>.
/**
* This module defines the events that are triggered in the message area.
*
* @module core_message/message_area_events
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define([], function() {
/** @type {Object} The list of events triggered in the message area. */
return {
CANCELDELETEMESSAGES: 'cancel-delete-messages',
CHOOSEMESSAGESTODELETE: 'choose-messages-to-delete',
CONTACTADDED: 'contact-added',
CONTACTBLOCKED: 'contact-blocked',
CONTACTREMOVED: 'contact-removed',
CONTACTSELECTED: 'contact-selected',
CONTACTSSELECTED: 'contacts-selected',
CONTACTUNBLOCKED: 'contact-unblocked',
CONVERSATIONDELETED: 'conversation-deleted',
CONVERSATIONSELECTED: 'conversation-selected',
CONVERSATIONSSELECTED: 'conversations-selected',
MESSAGESDELETED: 'messages-deleted',
MESSAGESEARCHCANCELED: 'message-search-canceled',
MESSAGESENT: 'message-sent',
SENDMESSAGE: 'message-send',
USERSSEARCHCANCELED: 'users-search-canceled'
};
});

View File

@ -1,876 +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/>.
/**
* This module handles the message area of the messaging area.
*
* @module core_message/message_area_messages
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/custom_interaction_events',
'core/auto_rows', 'core_message/message_area_actions', 'core/modal_factory', 'core/modal_events',
'core/str', 'core_message/message_area_events', 'core/backoff_timer'],
function($, Ajax, Templates, Notification, CustomEvents, AutoRows, Actions, ModalFactory,
ModalEvents, Str, Events, BackOffTimer) {
/** @type {int} The message area default height. */
var MESSAGES_AREA_DEFAULT_HEIGHT = 500;
/** @type {int} The response default height. */
var MESSAGES_RESPONSE_DEFAULT_HEIGHT = 50;
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
BLOCKTIME: "[data-region='blocktime']",
CANCELDELETEMESSAGES: "[data-action='cancel-delete-messages']",
CONTACT: "[data-region='contact']",
CONVERSATIONS: "[data-region='contacts'][data-region-content='conversations']",
DELETEALLMESSAGES: "[data-action='delete-all-messages']",
DELETEMESSAGES: "[data-action='delete-messages']",
LOADINGICON: '.loading-icon',
MESSAGE: "[data-region='message']",
MESSAGERESPONSE: "[data-region='response']",
MESSAGES: "[data-region='messages']",
MESSAGESAREA: "[data-region='messages-area']",
MESSAGINGAREA: "[data-region='messaging-area']",
SENDMESSAGE: "[data-action='send-message']",
SENDMESSAGETEXT: "[data-region='send-message-txt']",
SHOWCONTACTS: "[data-action='show-contacts']",
STARTDELETEMESSAGES: "[data-action='start-delete-messages']",
};
/** @type {int} The number of milliseconds in a second. */
var MILLISECONDSINSEC = 1000;
/**
* Messages class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Messages(messageArea) {
this.messageArea = messageArea;
this._init();
}
/** @type {Boolean} checks if we are sending a message */
Messages.prototype._isSendingMessage = false;
/** @type {Boolean} checks if we are currently loading messages */
Messages.prototype._isLoadingMessages = false;
/** @type {int} the number of messagess displayed */
Messages.prototype._numMessagesDisplayed = 0;
/** @type {array} the messages displayed or about to be displayed on the page */
Messages.prototype._messageQueue = [];
/** @type {int} the number of messages to retrieve */
Messages.prototype._numMessagesToRetrieve = 20;
/** @type {Modal} the confirmation modal */
Messages.prototype._confirmationModal = null;
/** @type {int} the timestamp for the most recent visible message */
Messages.prototype._latestMessageTimestamp = 0;
/** @type {BackOffTimer} the backoff timer */
Messages.prototype._backoffTimer = null;
/** @type {Messagearea} The messaging area object. */
Messages.prototype.messageArea = null;
/**
* Initialise the event listeners.
*
* @private
*/
Messages.prototype._init = function() {
CustomEvents.define(this.messageArea.node, [
CustomEvents.events.activate,
CustomEvents.events.up,
CustomEvents.events.down,
CustomEvents.events.enter,
]);
// We have a responsive media query based on height that reduces this size on screens shorter than 670.
if ($(window).height() <= 670) {
MESSAGES_AREA_DEFAULT_HEIGHT = 400;
}
AutoRows.init(this.messageArea.node);
this.messageArea.onCustomEvent(Events.CONVERSATIONSELECTED, this._viewMessages.bind(this));
this.messageArea.onCustomEvent(Events.SENDMESSAGE, this._viewMessages.bind(this));
this.messageArea.onCustomEvent(Events.CHOOSEMESSAGESTODELETE, this._chooseMessagesToDelete.bind(this));
this.messageArea.onCustomEvent(Events.CANCELDELETEMESSAGES, this._hideDeleteAction.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SENDMESSAGE,
this._sendMessage.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.STARTDELETEMESSAGES,
this._startDeleting.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.DELETEMESSAGES,
this._deleteMessages.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.DELETEALLMESSAGES,
this._deleteAllMessages.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.CANCELDELETEMESSAGES,
this._triggerCancelMessagesToDelete.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.MESSAGE,
this._toggleMessage.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SHOWCONTACTS,
this._hideMessagingArea.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.MESSAGE,
this._selectPreviousMessage.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.MESSAGE,
this._selectNextMessage.bind(this));
this.messageArea.onDelegateEvent('focus', SELECTORS.SENDMESSAGETEXT, this._setMessaging.bind(this));
this.messageArea.onDelegateEvent('blur', SELECTORS.SENDMESSAGETEXT, this._clearMessaging.bind(this));
$(document).on(AutoRows.events.ROW_CHANGE, this._adjustMessagesAreaHeight.bind(this));
// Check if any messages have been displayed on page load.
var messages = this.messageArea.find(SELECTORS.MESSAGES);
if (messages.length) {
this._addScrollEventListener(messages.find(SELECTORS.MESSAGE).length);
this._latestMessageTimestamp = messages.find(SELECTORS.MESSAGE + ':last').data('timecreated');
}
// Create a timer to poll the server for new messages.
this._backoffTimer = new BackOffTimer(this._loadNewMessages.bind(this),
BackOffTimer.getIncrementalCallback(this.messageArea.pollmin * MILLISECONDSINSEC, MILLISECONDSINSEC,
this.messageArea.pollmax * MILLISECONDSINSEC, this.messageArea.polltimeout * MILLISECONDSINSEC));
// Start the timer.
this._backoffTimer.start();
};
/**
* View the message panel.
*
* @param {Event} event
* @param {int} userid
* @return {Promise} The promise resolved when the messages have been loaded.
* @private
*/
Messages.prototype._viewMessages = function(event, userid) {
// We are viewing another user, or re-loading the panel, so set number of messages displayed to 0.
this._numMessagesDisplayed = 0;
// Stop the existing timer so we can set up the new user's messages.
this._backoffTimer.stop();
// Reset the latest timestamp when we change the messages view.
this._latestMessageTimestamp = 0;
// Mark all the messages as read.
var markMessagesAsRead = Ajax.call([{
methodname: 'core_message_mark_all_messages_as_read',
args: {
useridto: this.messageArea.getCurrentUserId(),
useridfrom: userid
}
}]);
// Keep track of the number of messages received.
var numberreceived = 0;
// Show loading template.
return Templates.render('core/loading', {}).then(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
return markMessagesAsRead[0];
}.bind(this)).then(function() {
var conversationnode = this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
SELECTORS.CONTACT + "[data-userid='" + userid + "']");
if (conversationnode.hasClass('unread')) {
// Remove the class.
conversationnode.removeClass('unread');
// Trigger an event letting the notification popover (and whoever else) know.
$(document).trigger('messagearea:conversationselected', userid);
}
return this._getMessages(userid);
}.bind(this)).then(function(data) {
numberreceived = data.messages.length;
// We have the data - lets render the template with it.
return Templates.render('core_message/message_area_messages_area', data);
}).then(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
this._addScrollEventListener(numberreceived);
// Restart the poll timer.
this._backoffTimer.restart();
this.messageArea.find(SELECTORS.SENDMESSAGETEXT).focus();
}.bind(this)).fail(Notification.exception);
};
/**
* Loads messages while scrolling.
*
* @return {Promise|boolean} The promise resolved when the messages have been loaded.
* @private
*/
Messages.prototype._loadMessages = function() {
if (this._isLoadingMessages) {
return false;
}
this._isLoadingMessages = true;
// Keep track of the number of messages received.
var numberreceived = 0;
// Show loading template.
return Templates.render('core/loading', {}).then(function(html, js) {
Templates.prependNodeContents(this.messageArea.find(SELECTORS.MESSAGES),
"<div style='text-align:center'>" + html + "</div>", js);
return this._getMessages(this._getUserId());
}.bind(this)).then(function(data) {
numberreceived = data.messages.length;
// We have the data - lets render the template with it.
return Templates.render('core_message/message_area_messages', data);
}).then(function(html, js) {
// Remove the loading icon.
this.messageArea.find(SELECTORS.MESSAGES + " " +
SELECTORS.LOADINGICON).remove();
// Check if we got something to do.
if (numberreceived > 0) {
var newHtml = $('<div>' + html + '</div>');
if (this._hasMatchingBlockTime(this.messageArea.node, newHtml, true)) {
this.messageArea.node.find(SELECTORS.BLOCKTIME + ':first').remove();
}
// Get height before we add the messages.
var oldheight = this.messageArea.find(SELECTORS.MESSAGES)[0].scrollHeight;
// Show the new content.
Templates.prependNodeContents(this.messageArea.find(SELECTORS.MESSAGES), html, js);
// Get height after we add the messages.
var newheight = this.messageArea.find(SELECTORS.MESSAGES)[0].scrollHeight;
// Make sure scroll bar is at the location before we loaded more messages.
this.messageArea.find(SELECTORS.MESSAGES).scrollTop(newheight - oldheight);
// Increment the number of messages displayed.
this._numMessagesDisplayed += numberreceived;
}
// Mark that we are no longer busy loading data.
this._isLoadingMessages = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Loads and renders messages newer than the most recently seen messages.
*
* @return {Promise|boolean} The promise resolved when the messages have been loaded.
* @private
*/
Messages.prototype._loadNewMessages = function() {
if (this._isLoadingMessages) {
return false;
}
// If we have no user id yet then bail early.
if (!this._getUserId()) {
return false;
}
this._isLoadingMessages = true;
// Only scroll the message window if the user hasn't scrolled up.
var shouldScrollBottom = false;
var messages = this.messageArea.find(SELECTORS.MESSAGES);
if (messages.length !== 0) {
var scrollTop = messages.scrollTop();
var innerHeight = messages.innerHeight();
var scrollHeight = messages[0].scrollHeight;
if (scrollTop + innerHeight >= scrollHeight) {
shouldScrollBottom = true;
}
}
// Keep track of the number of messages received.
return this._getMessages(this._getUserId(), true).then(function(data) {
return this._addMessagesToDom(data.messages, shouldScrollBottom);
}.bind(this)).always(function() {
// Mark that we are no longer busy loading data.
this._isLoadingMessages = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Handles returning a list of messages to display.
*
* @param {int} userid
* @param {bool} fromTimestamp Load messages from the latest known timestamp
* @return {Promise} The promise resolved when the contact area has been rendered
* @private
*/
Messages.prototype._getMessages = function(userid, fromTimestamp) {
var args = {
currentuserid: this.messageArea.getCurrentUserId(),
otheruserid: userid,
limitfrom: this._numMessagesDisplayed,
limitnum: this._numMessagesToRetrieve,
newest: true
};
// If we're trying to load new messages since the message UI was
// rendered. Used for ajax polling while user is on the message UI.
if (fromTimestamp) {
args.timefrom = this._latestMessageTimestamp;
// Remove limit and offset. We want all new messages.
args.limitfrom = 0;
args.limitnum = 0;
}
// Call the web service to get our data.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_messages',
args: args,
}]);
// Do stuff when we get data back.
return promises[0].then(function(data) {
var messages = data.messages;
// Did we get any new messages?
if (messages && messages.length) {
var latestMessage = messages[messages.length - 1];
// Update our record of the latest known message for future requests.
if (latestMessage.timecreated > this._latestMessageTimestamp) {
// Next request should be for the second after the most recent message we've seen.
this._latestMessageTimestamp = latestMessage.timecreated + 1;
}
}
return data;
}.bind(this)).fail(function(ex) {
// Stop the timer if we received an error so that we don't keep spamming the server.
this._backoffTimer.stop();
Notification.exception(ex);
}.bind(this));
};
/**
* Handles sending a message.
*
* @return {Promise|boolean} The promise resolved once the message has been sent.
* @private
*/
Messages.prototype._sendMessage = function() {
var element = this.messageArea.find(SELECTORS.SENDMESSAGETEXT);
var text = element.val().trim();
// Do not do anything if it is empty.
if (text === '') {
return false;
}
// If we are sending a message, don't do anything, be patient!
if (this._isSendingMessage) {
return false;
}
// Ok, mark that we are sending a message.
this._isSendingMessage = true;
// Call the web service to save our message.
var promises = Ajax.call([{
methodname: 'core_message_send_instant_messages',
args: {
messages: [
{
touserid: this._getUserId(),
text: text
}
]
}
}]);
element.prop('disabled', true);
// Update the DOM when we get some data back.
return promises[0].then(function(response) {
if (response.length < 0) {
// Even errors should return valid data.
throw new Error('Invalid response');
}
if (response[0].errormessage) {
throw new Error(response[0].errormessage);
}
// Fire an event to say the message was sent.
this.messageArea.trigger(Events.MESSAGESENT, [this._getUserId(), text]);
// Update the messaging area.
return this._addLastMessageToDom();
}.bind(this)).then(function() {
// Ok, we are no longer sending a message.
this._isSendingMessage = false;
}.bind(this)).always(function() {
element.prop('disabled', false);
element.focus();
}).fail(Notification.exception);
};
/**
* Handles selecting messages to delete.
*
* @private
*/
Messages.prototype._chooseMessagesToDelete = function() {
this.messageArea.find(SELECTORS.MESSAGESAREA).addClass('editing');
this.messageArea.find(SELECTORS.MESSAGE)
.attr('role', 'checkbox')
.attr('aria-checked', 'false');
};
/**
* Handles deleting messages.
*
* @private
*/
Messages.prototype._deleteMessages = function() {
var userid = this.messageArea.getCurrentUserId();
var checkboxes = this.messageArea.find(SELECTORS.MESSAGE + "[aria-checked='true']");
var requests = [];
var messagestoremove = [];
// Go through all the checked checkboxes and prepare them for deletion.
checkboxes.each(function(id, element) {
var node = $(element);
var messageid = node.data('messageid');
var isread = node.data('messageread') ? 1 : 0;
messagestoremove.push(node);
requests.push({
methodname: 'core_message_delete_message',
args: {
messageid: messageid,
userid: userid,
read: isread
}
});
});
if (requests.length > 0) {
$.when(Ajax.call(requests)).then(function() {
// Store the last message on the page, and the last message being deleted.
var updatemessage = null;
var messages = this.messageArea.find(SELECTORS.MESSAGE);
var lastmessage = messages.last();
var lastremovedmessage = messagestoremove[messagestoremove.length - 1];
// Remove the messages from the DOM.
$.each(messagestoremove, function(key, message) {
// Remove the message.
message.remove();
});
// If the last message was deleted then we need to provide the new last message.
if (lastmessage.data('id') === lastremovedmessage.data('id')) {
updatemessage = this.messageArea.find(SELECTORS.MESSAGE).last();
}
// Now we have removed all the messages from the DOM lets remove any block times we may need to as well.
$.each(messagestoremove, function(key, message) {
// First - let's make sure there are no more messages in that time block.
var blocktime = message.data('blocktime');
if (this.messageArea.find(SELECTORS.MESSAGE +
"[data-blocktime='" + blocktime + "']").length === 0) {
this.messageArea.find(SELECTORS.BLOCKTIME +
"[data-blocktime='" + blocktime + "']").remove();
}
}.bind(this));
// If there are no messages at all, then remove conversation panel.
if (this.messageArea.find(SELECTORS.MESSAGE).length === 0) {
this.messageArea.find(SELECTORS.CONVERSATIONS + " " +
SELECTORS.CONTACT + "[data-userid='" + this._getUserId() + "']").remove();
}
// Trigger event letting other modules know messages were deleted.
this.messageArea.trigger(Events.MESSAGESDELETED, [this._getUserId(), updatemessage]);
}.bind(this)).catch(Notification.exception);
} else {
// Trigger event letting other modules know messages were deleted.
this.messageArea.trigger(Events.MESSAGESDELETED, this._getUserId());
}
// Hide the items responsible for deleting messages.
this._hideDeleteAction();
};
/**
* Handles adding a scrolling event listener.
*
* @param {int} numberreceived The number of messages received
* @private
*/
Messages.prototype._addScrollEventListener = function(numberreceived) {
// Scroll to the bottom.
this._scrollBottom();
// Set the number of messages displayed.
this._numMessagesDisplayed = numberreceived;
// Now enable the ability to infinitely scroll through messages.
CustomEvents.define(this.messageArea.find(SELECTORS.MESSAGES), [
CustomEvents.events.scrollTop
]);
// Assign the event for scrolling.
this.messageArea.onCustomEvent(CustomEvents.events.scrollTop, this._loadMessages.bind(this));
};
/**
* Handles deleting a conversation.
*
* @private
*/
Messages.prototype._deleteAllMessages = function() {
if (this._confirmationModal) {
// Just show the existing modal.
this._confirmationModal.show();
return;
}
var stringsPromise = Str.get_strings([
{key: 'confirm'},
{key: 'deleteallconfirm', component: 'message'},
{key: 'delete'}
]);
var deleteModalPromise = ModalFactory.create(
{
type: ModalFactory.types.SAVE_CANCEL
},
this.messageArea.find(SELECTORS.DELETEALLMESSAGES)
);
$.when(stringsPromise, deleteModalPromise).then(function(s, modal) {
modal.setTitle(s[0]);
modal.setBody(s[1]);
modal.setSaveButtonText(s[2]);
this._confirmationModal = modal;
// Only delete the conversation if the user agreed in the confirmation modal.
modal.getRoot().on(ModalEvents.save, function() {
var otherUserId = this._getUserId();
var request = {
methodname: 'core_message_delete_conversation',
args: {
userid: this.messageArea.getCurrentUserId(),
otheruserid: otherUserId
}
};
// Delete the conversation.
Ajax.call([request])[0].then(function() {
// Clear the message area.
this.messageArea.find(SELECTORS.MESSAGESAREA).empty();
// Let the app know a conversation was deleted.
this.messageArea.trigger(Events.CONVERSATIONDELETED, otherUserId);
this._hideDeleteAction();
}.bind(this)).catch(Notification.exception);
}.bind(this));
// Display the confirmation.
modal.show();
}.bind(this)).catch(Notification.exception);
};
/**
* Handles hiding the delete checkboxes and replacing the response area.
*
* @private
*/
Messages.prototype._hideDeleteAction = function() {
this.messageArea.find(SELECTORS.MESSAGE)
.removeAttr('role')
.removeAttr('aria-checked');
this.messageArea.find(SELECTORS.MESSAGESAREA).removeClass('editing');
};
/**
* Triggers the CANCELDELETEMESSAGES event.
*
* @private
*/
Messages.prototype._triggerCancelMessagesToDelete = function() {
// Trigger event letting other modules know message deletion was canceled.
this.messageArea.trigger(Events.CANCELDELETEMESSAGES);
};
/**
* Handles adding messages to the DOM.
*
* @param {array} messages An array of messages to be added to the DOM.
* @param {boolean} shouldScrollBottom True will scroll to the bottom of the message window and show the new messages.
* @return {Promise} The promise resolved when the messages have been added to the DOM.
* @private
*/
Messages.prototype._addMessagesToDom = function(messages, shouldScrollBottom) {
var numberreceived = 0;
var messagesArea = this.messageArea.find(SELECTORS.MESSAGES);
messages = messages.filter(function(message) {
var id = "" + message.id + message.isread;
// If the message is already queued to be rendered, remove from the list of messages.
if (this._messageQueue[id]) {
return false;
}
// Filter out any messages already rendered.
var result = messagesArea.find(SELECTORS.MESSAGE + '[data-id="' + id + '"]');
// Any message we are rendering should go in the messageQueue.
if (!result.length) {
this._messageQueue[id] = true;
}
return !result.length;
}.bind(this));
numberreceived = messages.length;
// We have the data - lets render the template with it.
return Templates.render('core_message/message_area_messages', {messages: messages}).then(function(html, js) {
// Check if we got something to do.
if (numberreceived > 0) {
var newHtml = $('<div>' + html + '</div>');
if (this._hasMatchingBlockTime(this.messageArea.node, newHtml, false)) {
newHtml.find(SELECTORS.BLOCKTIME + ':first').remove();
}
// Show the new content.
Templates.appendNodeContents(this.messageArea.find(SELECTORS.MESSAGES), newHtml, js);
// Scroll the new message into view.
if (shouldScrollBottom) {
this._scrollBottom();
}
// Increment the number of messages displayed.
this._numMessagesDisplayed += numberreceived;
// Reset the poll timer because the user may be active.
this._backoffTimer.restart();
}
}.bind(this));
};
/**
* Handles adding the last message to the DOM.
*
* @return {Promise} The promise resolved when the message has been added to the DOM.
* @private
*/
Messages.prototype._addLastMessageToDom = function() {
// Call the web service to return how the message should look.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_get_most_recent_message',
args: {
currentuserid: this.messageArea.getCurrentUserId(),
otheruserid: this._getUserId()
}
}]);
// Add the message.
return promises[0].then(function(data) {
return this._addMessagesToDom([data], true);
}.bind(this)).always(function() {
// Empty the response text area.text
this.messageArea.find(SELECTORS.SENDMESSAGETEXT).val('').trigger('input');
}.bind(this)).fail(Notification.exception);
};
/**
* Returns the ID of the other user in the conversation.
*
* @return {int} The user id
* @private
*/
Messages.prototype._getUserId = function() {
return this.messageArea.find(SELECTORS.MESSAGES).data('userid');
};
/**
* Scrolls to the bottom of the messages.
*
* @private
*/
Messages.prototype._scrollBottom = function() {
// Scroll to the bottom.
var messages = this.messageArea.find(SELECTORS.MESSAGES);
if (messages.length !== 0) {
messages.scrollTop(messages[0].scrollHeight);
}
};
/**
* Select the previous message in the list.
*
* @param {event} e The jquery event
* @param {object} data Extra event data
* @private
*/
Messages.prototype._selectPreviousMessage = function(e, data) {
var currentMessage = $(e.target).closest(SELECTORS.MESSAGE);
do {
currentMessage = currentMessage.prev();
} while (currentMessage.length && !currentMessage.is(SELECTORS.MESSAGE));
currentMessage.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Select the next message in the list.
*
* @param {event} e The jquery event
* @param {object} data Extra event data
* @private
*/
Messages.prototype._selectNextMessage = function(e, data) {
var currentMessage = $(e.target).closest(SELECTORS.MESSAGE);
do {
currentMessage = currentMessage.next();
} while (currentMessage.length && !currentMessage.is(SELECTORS.MESSAGE));
currentMessage.focus();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
/**
* Flag the response area as messaging.
*
* @param {event} e The jquery event
* @private
*/
Messages.prototype._setMessaging = function(e) {
$(e.target).closest(SELECTORS.MESSAGERESPONSE).addClass('messaging');
};
/**
* Clear the response area as messaging flag.
*
* @param {event} e The jquery event
* @private
*/
Messages.prototype._clearMessaging = function(e) {
$(e.target).closest(SELECTORS.MESSAGERESPONSE).removeClass('messaging');
};
/**
* Turn on delete message mode.
*
* @param {event} e The jquery event
* @private
*/
Messages.prototype._startDeleting = function(e) {
var actions = new Actions(this.messageArea);
actions.chooseMessagesToDelete();
e.preventDefault();
};
/**
* Check if the message area is in editing mode.
*
* @return {bool}
* @private
*/
Messages.prototype._isEditing = function() {
return this.messageArea.find(SELECTORS.MESSAGESAREA).hasClass('editing');
};
/**
* Check or uncheck the message if the message area is in editing mode.
*
* @param {event} e The jquery event
* @private
*/
Messages.prototype._toggleMessage = function(e) {
if (!this._isEditing()) {
return;
}
var message = $(e.target).closest(SELECTORS.MESSAGE);
if (message.attr('aria-checked') === 'true') {
message.attr('aria-checked', 'false');
} else {
message.attr('aria-checked', 'true');
}
};
/**
* Adjust the height of the messages area to match the changed height of
* the response area.
*
* @private
*/
Messages.prototype._adjustMessagesAreaHeight = function() {
var messagesArea = this.messageArea.find(SELECTORS.MESSAGES);
var messagesResponse = this.messageArea.find(SELECTORS.MESSAGERESPONSE);
var currentMessageResponseHeight = messagesResponse.outerHeight();
var diffResponseHeight = currentMessageResponseHeight - MESSAGES_RESPONSE_DEFAULT_HEIGHT;
var newMessagesAreaHeight = MESSAGES_AREA_DEFAULT_HEIGHT - diffResponseHeight;
messagesArea.outerHeight(newMessagesAreaHeight);
};
/**
* Handle the event that triggers sending a message from the messages area.
*
* @param {event} e The jquery event
* @param {object} data Additional event data
* @private
*/
Messages.prototype._sendMessageHandler = function(e, data) {
data.originalEvent.preventDefault();
this._sendMessage();
};
/**
* Hide the messaging area. This only applies on smaller screen resolutions.
*
* @private
*/
Messages.prototype._hideMessagingArea = function() {
this.messageArea.find(SELECTORS.MESSAGINGAREA)
.removeClass('show-messages')
.addClass('hide-messages');
};
/**
* Checks if a day separator needs to be removed.
*
* Example - scrolling up and loading previous messages that belong to the
* same day as the last message that was previously shown, meaning we can
* remove the original separator.
*
* @param {jQuery} domHtml The HTML in the DOM.
* @param {jQuery} newHtml The HTML to compare to the DOM
* @param {boolean} loadingPreviousMessages Are we loading previous messages?
* @return {boolean}
* @private
*/
Messages.prototype._hasMatchingBlockTime = function(domHtml, newHtml, loadingPreviousMessages) {
var blockTime, blockTimePos, newBlockTime, newBlockTimePos;
if (loadingPreviousMessages) {
blockTimePos = ':first';
newBlockTimePos = ':last';
} else {
blockTimePos = ':last';
newBlockTimePos = ':first';
}
blockTime = domHtml.find(SELECTORS.BLOCKTIME + blockTimePos);
newBlockTime = newHtml.find(SELECTORS.BLOCKTIME + newBlockTimePos);
if (blockTime.length && newBlockTime.length) {
return blockTime.data('blocktime') == newBlockTime.data('blocktime');
}
return false;
};
return Messages;
}
);

View File

@ -1,304 +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/>.
/**
* This module handles the profile area of the messaging area.
*
* @module core_message/message_area_profile
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/config',
'core/custom_interaction_events', 'core_message/message_area_events'],
function($, Ajax, Templates, Notification, Str, Config, CustomEvents, Events) {
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
PROFILE: "[data-region='profile']",
PROFILEADDCONTACT: "[data-action='profile-add-contact']",
PROFILEBLOCKCONTACT: "[data-action='profile-block-contact']",
PROFILEREMOVECONTACT: "[data-action='profile-remove-contact']",
PROFILESENDMESSAGE: "[data-action='profile-send-message']",
PROFILEUNBLOCKCONTACT: "[data-action='profile-unblock-contact']",
PROFILEVIEW: "[data-action='profile-view']",
SHOWCONTACTS: "[data-action='show-contacts']",
MESSAGESAREA: "[data-region='messages-area']",
MESSAGINGAREA: "[data-region='messaging-area']"
};
/**
* Profile class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Profile(messageArea) {
this.messageArea = messageArea;
this._init();
}
/** @type {Messagearea} The messaging area object. */
Profile.prototype.messageArea = null;
/**
* Initialise the event listeners.
*
* @private
*/
Profile.prototype._init = function() {
CustomEvents.define(this.messageArea.node, [
CustomEvents.events.activate
]);
this.messageArea.onCustomEvent(Events.CONTACTSELECTED, this._viewProfile.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILEVIEW,
function(e, data) {
this._viewFullProfile();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILESENDMESSAGE,
function(e, data) {
this._sendMessage();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILEUNBLOCKCONTACT,
function(e, data) {
this._unblockContact();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILEBLOCKCONTACT,
function(e, data) {
this._blockContact();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILEADDCONTACT,
function(e, data) {
this._addContact();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.PROFILEREMOVECONTACT,
function(e, data) {
this._removeContact();
data.originalEvent.preventDefault();
}.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SHOWCONTACTS,
this._hideMessagingArea.bind(this));
};
/**
* Handles viewing the profile.
*
* @param {Event} event
* @param {int} userid
* @return {Promise} The promise resolved when the profile has been rendered
* @private
*/
Profile.prototype._viewProfile = function(event, userid) {
// Show loading template.
Templates.render('core/loading', {}).done(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
}.bind(this));
// Call the web service to return the profile.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_get_profile',
args: {
currentuserid: this.messageArea.getCurrentUserId(),
otheruserid: userid
}
}]);
// Show the profile.
return promises[0].then(function(data) {
return Templates.render('core_message/message_area_profile', data);
}).then(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.MESSAGESAREA), html, js);
}.bind(this)).fail(Notification.exception);
};
/**
* Handles viewing the user's full profile.
*
* @private
*/
Profile.prototype._viewFullProfile = function() {
window.location.href = Config.wwwroot + '/user/profile.php?id=' + this._getUserId();
};
/**
* Handles viewing the messages with the user.
*
* @private
*/
Profile.prototype._sendMessage = function() {
this.messageArea.trigger(Events.SENDMESSAGE, this._getUserId());
};
/**
* Handles blocking the contact.
*
* @return {Promise} The promise resolved when the contact has been blocked
* @private
*/
Profile.prototype._blockContact = function() {
var action = this._performAction('core_message_block_user', 'unblockcontact', 'profile-block-contact',
'profile-unblock-contact', '');
return action.then(function() {
this.messageArea.trigger(Events.CONTACTBLOCKED, this._getUserId());
}.bind(this));
};
/**
* Handles unblocking the contact.
*
* @return {Promise} The promise resolved when the contact has been unblocked
* @private
*/
Profile.prototype._unblockContact = function() {
var action = this._performAction('core_message_unblock_user', 'blockcontact', 'profile-unblock-contact',
'profile-block-contact', 'danger');
return action.then(function() {
this.messageArea.trigger(Events.CONTACTUNBLOCKED, this._getUserId());
}.bind(this));
};
/**
* Handles adding the contact.
*
* @return {Promise} The promise resolved when the contact has been added
* @private
*/
Profile.prototype._addContact = function() {
var action = this._performAction('core_message_create_contact_request', 'removecontact', 'profile-add-contact',
'profile-remove-contact', 'danger');
return action.then(function() {
this.messageArea.trigger(Events.CONTACTADDED, this._getUserId());
}.bind(this));
};
/**
* Handles removing the contact.
*
* @return {Promise} The promise resolved when the contact has been removed
* @private
*/
Profile.prototype._removeContact = function() {
var action = this._performAction('core_message_delete_contacts', 'addcontact', 'profile-remove-contact',
'profile-add-contact', '');
return action.then(function() {
this.messageArea.trigger(Events.CONTACTREMOVED, this._getUserId());
}.bind(this));
};
/**
* Helper function to perform actions on the profile page.
*
* @param {String} service The web service to call.
* @param {String} string The string to change the button value to
* @param {String} oldaction The data-action of the button
* @param {string} newaction The data-action to change the button to
* @param {String} newclass The CSS class we want to add
* @return {Promise} The promise resolved when the action has been performed
* @private
*/
Profile.prototype._performAction = function(service, string, oldaction, newaction, newclass) {
// This is a temporary hack as we are getting rid of this UI.
var userargs = '';
switch (service) {
case 'core_message_block_user':
userargs = {
userid: this.messageArea.getCurrentUserId(),
blockeduserid: this._getUserId()
};
break;
case 'core_message_unblock_user':
userargs = {
userid: this.messageArea.getCurrentUserId(),
unblockeduserid: this._getUserId()
};
break;
case 'core_message_create_contact_request':
userargs = {
userid: this.messageArea.getCurrentUserId(),
requesteduserid: this._getUserId()
};
break;
default:
userargs = {
userid: this.messageArea.getCurrentUserId(),
userids: [
this._getUserId()
]
};
}
var promises = Ajax.call([{
methodname: service,
args: userargs
}]);
return promises[0].then(function() {
return Str.get_string(string, 'message');
}).then(function(s) {
this._changeText(s, oldaction, newaction, newclass);
}.bind(this)).fail(Notification.exception);
};
/**
* Changes the text in the profile area.
*
* @param {String} text The string to change the button value to
* @param {string} oldaction The data-action of the button
* @param {string} newaction The data-action to change the button to
* @param {String} newclass The CSS class we want to add
* @private
*/
Profile.prototype._changeText = function(text, oldaction, newaction, newclass) {
var anchor = this.messageArea.find("[data-action='" + oldaction + "']");
// Change the text.
anchor.text(text);
// Remove any class.
anchor.removeClass();
// Add the class if there is one.
if (newclass) {
anchor.addClass(newclass);
}
anchor.attr('data-action', newaction);
};
/**
* Returns the ID of the user whos profile we are viewing.
*
* @return {int} The user ID
* @private
*/
Profile.prototype._getUserId = function() {
return this.messageArea.find(SELECTORS.PROFILE).data('userid');
};
/**
* Hide the messaging area. This only applies on smaller screen resolutions.
*/
Profile.prototype._hideMessagingArea = function() {
this.messageArea.find(SELECTORS.MESSAGINGAREA)
.removeClass('show-messages')
.addClass('hide-messages');
};
return Profile;
}
);

View File

@ -1,425 +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/>.
/**
* The module handles searching contacts.
*
* @module core_message/message_area_search
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/templates', 'core/notification', 'core/str', 'core/custom_interaction_events',
'core_message/message_area_events'],
function($, Ajax, Templates, Notification, Str, CustomEvents, Events) {
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
CONTACTS: "[data-region='contacts'][data-region-content='contacts']",
CONTACTSAREA: "[data-region='contacts-area']",
CONVERSATIONS: "[data-region='contacts'][data-region-content='conversations']",
DELETESEARCHFILTER: "[data-region='search-filter-area']",
LOADINGICON: '.loading-icon',
SEARCHBOX: "[data-region='search-box']",
SEARCHFILTER: "[data-region='search-filter']",
SEARCHFILTERAREA: "[data-region='search-filter-area']",
SEARCHRESULTSAREA: "[data-region='search-results-area']",
SEARCHTEXTAREA: "[data-region='search-text-area']",
SEARCHUSERSINCOURSE: "[data-action='search-users-in-course']",
};
/**
* Search class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Search(messageArea) {
this.messageArea = messageArea;
this._init();
}
/** @type {Messagearea} The messaging area object. */
Search.prototype.messageArea = null;
/** @type {String} The area we are searching in. */
Search.prototype._searchArea = null;
/** @type {String} The id of the course we are searching in (if any). */
Search.prototype._courseid = null;
/** @type {Boolean} checks if we are currently loading */
Search.prototype._isLoading = false;
/** @type {String} The number of messages displayed. */
Search.prototype._numMessagesDisplayed = 0;
/** @type {String} The number of messages to retrieve. */
Search.prototype._numMessagesToRetrieve = 20;
/** @type {String} The number of users displayed. */
Search.prototype._numUsersDisplayed = 0;
/** @type {String} The number of users to retrieve. */
Search.prototype._numUsersToRetrieve = 20;
/** @type {Array} The type of available search areas. **/
Search.prototype._searchAreas = {
MESSAGES: 'messages',
USERS: 'users',
USERSINCOURSE: 'usersincourse'
};
/** @type {int} The timeout before performing an ajax search */
Search.prototype._requestTimeout = null;
/**
* Initialise the event listeners.
*
* @private
*/
Search.prototype._init = function() {
// Handle searching for text.
this.messageArea.find(SELECTORS.SEARCHTEXTAREA).on('input', this._searchRequest.bind(this));
// Handle clicking on a course in the list of users.
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.SEARCHUSERSINCOURSE, function(e) {
this._setFilter($(e.currentTarget).html());
this._setPlaceholderText('searchforuser');
this._clearSearchArea();
this._searchArea = this._searchAreas.USERSINCOURSE;
this._courseid = $(e.currentTarget).data('courseid');
this._searchUsersInCourse();
this.messageArea.find(SELECTORS.SEARCHBOX).focus();
}.bind(this));
// Handle deleting the search filter.
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.DELETESEARCHFILTER, function() {
this._hideSearchResults();
// Filter has been removed, so we don't want to be searching in a course anymore.
this._searchArea = this._searchAreas.USERS;
this._setPlaceholderText('searchforuserorcourse');
// Go back the contacts.
this.messageArea.trigger(Events.USERSSEARCHCANCELED);
this.messageArea.find(SELECTORS.SEARCHBOX).focus();
}.bind(this));
// Handle events that occur outside this module.
this.messageArea.onCustomEvent(Events.CONVERSATIONSSELECTED, function() {
this._hideSearchResults();
this._searchArea = this._searchAreas.MESSAGES;
this._setPlaceholderText('searchmessages');
}.bind(this));
this.messageArea.onCustomEvent(Events.CONTACTSSELECTED, function() {
this._hideSearchResults();
this._searchArea = this._searchAreas.USERS;
this._setPlaceholderText('searchforuserorcourse');
}.bind(this));
this.messageArea.onCustomEvent(Events.MESSAGESENT, function() {
this._hideSearchResults();
this._searchArea = this._searchAreas.MESSAGES;
this._setPlaceholderText('searchmessages');
}.bind(this));
// Event listeners for scrolling through messages and users in courses.
CustomEvents.define(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), [
CustomEvents.events.scrollBottom
]);
this.messageArea.onDelegateEvent(CustomEvents.events.scrollBottom, SELECTORS.SEARCHRESULTSAREA,
function() {
if (this._searchArea == this._searchAreas.MESSAGES) {
this._searchMessages();
} else if (this._searchArea == this._searchAreas.USERSINCOURSE) {
this._searchUsersInCourse();
}
}.bind(this)
);
// Set the initial search area.
this._searchArea = (this.messageArea.showContactsFirst()) ? this._searchAreas.USERS : this._searchAreas.MESSAGES;
};
/**
* Handles when search requests are sent.
*
* @private
*/
Search.prototype._searchRequest = function() {
var str = this.messageArea.find(SELECTORS.SEARCHTEXTAREA + ' input').val();
if (this._requestTimeout) {
clearTimeout(this._requestTimeout);
}
if (str.trim() === '') {
// If nothing we being searched then we need to display the usual data.
if (this._searchArea == this._searchAreas.MESSAGES) {
this._hideSearchResults();
this.messageArea.trigger(Events.MESSAGESEARCHCANCELED);
} else if (this._searchArea == this._searchAreas.USERS) {
this._hideSearchResults();
this.messageArea.trigger(Events.USERSSEARCHCANCELED);
} else if (this._searchArea == this._searchAreas.USERSINCOURSE) {
// We are still searching in a course, so need to list all the users again.
this._clearSearchArea();
this._searchUsersInCourse();
}
return;
}
this.messageArea.find(SELECTORS.CONVERSATIONS).hide();
this.messageArea.find(SELECTORS.CONTACTS).hide();
this.messageArea.find(SELECTORS.SEARCHRESULTSAREA).show();
if (this._searchArea == this._searchAreas.MESSAGES) {
this._requestTimeout = setTimeout(function() {
this._clearSearchArea();
this._numMessagesDisplayed = 0;
this._searchMessages();
}.bind(this), 300);
} else if (this._searchArea == this._searchAreas.USERSINCOURSE) {
this._requestTimeout = setTimeout(function() {
this._clearSearchArea();
this._numUsersDisplayed = 0;
this._searchUsersInCourse();
}.bind(this), 300);
} else { // Must be searching for users and courses
this._requestTimeout = setTimeout(function() {
this._clearSearchArea();
this._numUsersDisplayed = 0;
this._searchUsers();
}.bind(this), 300);
}
};
/**
* Handles searching for messages.
*
* @private
* @return {Promise|boolean} The promise resolved when the search area has been rendered
*/
Search.prototype._searchMessages = function() {
if (this._isLoading) {
return false;
}
var str = this.messageArea.find(SELECTORS.SEARCHBOX).val();
// Tell the user we are loading items.
this._isLoading = true;
// Call the web service to get our data.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_search_messages',
args: {
userid: this.messageArea.getCurrentUserId(),
search: str,
limitfrom: this._numMessagesDisplayed,
limitnum: this._numMessagesToRetrieve
}
}]);
// Keep track of the number of messages
var numberreceived = 0;
// Add loading icon to the end of the list.
return Templates.render('core/loading', {}).then(function(html, js) {
Templates.appendNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA),
"<div style='text-align:center'>" + html + "</div>", js);
return promises[0];
}.bind(this)).then(function(data) {
numberreceived = data.contacts.length;
return Templates.render('core_message/message_area_message_search_results', data);
}).then(function(html, js) {
// Remove the loading icon.
this.messageArea.find(SELECTORS.SEARCHRESULTSAREA + " " +
SELECTORS.LOADINGICON).remove();
// Only append data if we got data back.
if (numberreceived > 0) {
// Show the new content.
Templates.appendNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), html, js);
// Increment the number of contacts displayed.
this._numMessagesDisplayed += numberreceived;
} else if (this._numMessagesDisplayed == 0) { // Must have nothing to begin with.
// Replace the new content.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), html, js);
}
// Mark that we are no longer busy loading data.
this._isLoading = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Handles searching for users.
*
* @private
* @return {Promise} The promise resolved when the search area has been rendered
*/
Search.prototype._searchUsers = function() {
var str = this.messageArea.find(SELECTORS.SEARCHBOX).val();
// Call the web service to get our data.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_search_users',
args: {
userid: this.messageArea.getCurrentUserId(),
search: str,
limitnum: this._numUsersToRetrieve
}
}]);
// Perform the search and replace the content.
return Templates.render('core/loading', {}).then(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA),
"<div style='text-align:center'>" + html + "</div>", js);
return promises[0];
}.bind(this)).then(function(data) {
if (data.contacts.length > 0) {
data.hascontacts = true;
}
if (data.courses.length > 0) {
data.hascourses = true;
}
if (data.noncontacts.length > 0) {
data.hasnoncontacts = true;
}
return Templates.render('core_message/message_area_user_search_results', data);
}).then(function(html, js) {
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), html, js);
}.bind(this)).fail(Notification.exception);
};
/**
* Handles searching for users in a course.
*
* @private
* @return {Promise|boolean} The promise resolved when the search area has been rendered
*/
Search.prototype._searchUsersInCourse = function() {
if (this._isLoading) {
return false;
}
var str = this.messageArea.find(SELECTORS.SEARCHBOX).val();
// Tell the user we are loading items.
this._isLoading = true;
// Call the web service to get our data.
var promises = Ajax.call([{
methodname: 'core_message_data_for_messagearea_search_users_in_course',
args: {
userid: this.messageArea.getCurrentUserId(),
courseid: this._courseid,
search: str,
limitfrom: this._numUsersDisplayed,
limitnum: this._numUsersToRetrieve
}
}]);
// Keep track of the number of contacts
var numberreceived = 0;
// Add loading icon to the end of the list.
return Templates.render('core/loading', {}).then(function(html, js) {
Templates.appendNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA),
"<div style='text-align:center'>" + html + "</div>", js);
return promises[0];
}.bind(this)).then(function(data) {
numberreceived = data.contacts.length;
if (numberreceived > 0) {
data.hascontacts = true;
}
return Templates.render('core_message/message_area_user_search_results', data);
}).then(function(html, js) {
// Remove the loading icon.
this.messageArea.find(SELECTORS.SEARCHRESULTSAREA + " " +
SELECTORS.LOADINGICON).remove();
// Only append data if we got data back.
if (numberreceived > 0) {
// Show the new content.
Templates.appendNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), html, js);
// Increment the number of contacts displayed.
this._numUsersDisplayed += numberreceived;
} else if (this._numUsersDisplayed == 0) { // Must have nothing to begin with.
// Replace the new content.
Templates.replaceNodeContents(this.messageArea.find(SELECTORS.SEARCHRESULTSAREA), html, js);
}
// Mark that we are no longer busy loading data.
this._isLoading = false;
}.bind(this)).fail(Notification.exception);
};
/**
* Sets placeholder text for search input.
*
* @private
* @param {String} text The placeholder text
* @return {Promise} The promise resolved when the placeholder text has been set
*/
Search.prototype._setPlaceholderText = function(text) {
return Str.get_string(text, 'message').then(function(s) {
this.messageArea.find(SELECTORS.SEARCHTEXTAREA + ' input').attr('placeholder', s);
}.bind(this));
};
/**
* Sets filter for search input.
*
* @private
* @param {String} text The filter text
*/
Search.prototype._setFilter = function(text) {
this.messageArea.find(SELECTORS.SEARCHBOX).val('');
this.messageArea.find(SELECTORS.CONTACTSAREA).addClass('searchfilter');
this.messageArea.find(SELECTORS.SEARCHFILTERAREA).show();
this.messageArea.find(SELECTORS.SEARCHFILTER).html(text);
Str.get_string('removecoursefilter', 'message', text).then(function(languagestring) {
this.messageArea.find(SELECTORS.SEARCHFILTERAREA).attr('aria-label', languagestring);
}.bind(this)).catch(Notification.exception);
};
/**
* Hides filter for search input.
*
* @private
*/
Search.prototype._clearFilters = function() {
this.messageArea.find(SELECTORS.CONTACTSAREA).removeClass('searchfilter');
this.messageArea.find(SELECTORS.SEARCHFILTER).empty();
this.messageArea.find(SELECTORS.SEARCHFILTERAREA).hide();
this.messageArea.find(SELECTORS.SEARCHFILTERAREA).removeAttr('aria-label');
};
/**
* Handles clearing the search area.
*
* @private
*/
Search.prototype._clearSearchArea = function() {
this.messageArea.find(SELECTORS.SEARCHRESULTSAREA).empty();
};
/**
* Handles hiding the search area.
*
* @private
*/
Search.prototype._hideSearchResults = function() {
this._clearFilters();
this.messageArea.find(SELECTORS.SEARCHTEXTAREA + ' input').val('');
this._clearSearchArea();
this.messageArea.find(SELECTORS.SEARCHRESULTSAREA).hide();
};
return Search;
});

View File

@ -1,161 +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/>.
/**
* This module handles the tabs of the messaging area.
*
* @module core_message/message_area_tabs
* @package core_message
* @copyright 2016 Mark Nelson <markn@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['core/custom_interaction_events', 'core_message/message_area_events'], function(CustomEvents, Events) {
/** @type {Object} The list of selectors for the message area. */
var SELECTORS = {
ACTIVECONTACTSTAB: "[data-region='contacts-area'] [role='tab'][aria-selected='true']",
CONTACTSPANELS: "[data-region='contacts']",
VIEWCONTACTS: "[data-action='contacts-view']",
VIEWCONVERSATIONS: "[data-action='conversations-view']"
};
/**
* Tabs class.
*
* @param {Messagearea} messageArea The messaging area object.
*/
function Tabs(messageArea) {
this.messageArea = messageArea;
this._init();
}
/** @type {Messagearea} The messaging area object. */
Tabs.prototype.messageArea = null;
/**
* Initialise the event listeners.
*
* @private
*/
Tabs.prototype._init = function() {
CustomEvents.define(this.messageArea.node, [
CustomEvents.events.activate,
CustomEvents.events.up,
CustomEvents.events.down,
CustomEvents.events.next,
CustomEvents.events.previous,
CustomEvents.events.ctrlPageUp,
CustomEvents.events.ctrlPageDown,
]);
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.VIEWCONVERSATIONS,
this._viewConversations.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.activate, SELECTORS.VIEWCONTACTS,
this._viewContacts.bind(this));
// Change to the other tab if any arrow keys are pressed, since there are only two tabs.
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.VIEWCONVERSATIONS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.VIEWCONVERSATIONS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.next, SELECTORS.VIEWCONVERSATIONS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.previous, SELECTORS.VIEWCONVERSATIONS,
this._toggleTabs.bind(this));
// Change to the other tab if any arrow keys are pressed, since there are only two tabs.
this.messageArea.onDelegateEvent(CustomEvents.events.up, SELECTORS.VIEWCONTACTS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.down, SELECTORS.VIEWCONTACTS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.next, SELECTORS.VIEWCONTACTS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.previous, SELECTORS.VIEWCONTACTS,
this._toggleTabs.bind(this));
// Tab panel keyboard handling.
this.messageArea.onDelegateEvent(CustomEvents.events.ctrlPageUp, SELECTORS.CONTACTSPANELS,
this._toggleTabs.bind(this));
this.messageArea.onDelegateEvent(CustomEvents.events.ctrlPageDown, SELECTORS.CONTACTSPANELS,
this._toggleTabs.bind(this));
this.messageArea.onCustomEvent(Events.MESSAGESENT, function() {
this._selectTab(SELECTORS.VIEWCONVERSATIONS, SELECTORS.VIEWCONTACTS);
}.bind(this));
};
/**
* Handles when the conversation tab is selected.
*
* @private
*/
Tabs.prototype._viewConversations = function() {
this.messageArea.trigger(Events.CONVERSATIONSSELECTED);
this._selectTab(SELECTORS.VIEWCONVERSATIONS, SELECTORS.VIEWCONTACTS);
};
/**
* Handles when the contacts tab is selected.
*
* @private
*/
Tabs.prototype._viewContacts = function() {
this.messageArea.trigger(Events.CONTACTSSELECTED);
this._selectTab(SELECTORS.VIEWCONTACTS, SELECTORS.VIEWCONVERSATIONS);
};
/**
* Sets a tab to selected.
*
* @param {String} tabselect The name of the tab to select
* @param {String} tabdeselect The name of the tab to deselect
* @private
*/
Tabs.prototype._selectTab = function(tabselect, tabdeselect) {
tabdeselect = this.messageArea.find(tabdeselect);
tabdeselect.removeClass('selected');
tabdeselect.attr('aria-selected', 'false');
tabdeselect.attr('tabindex', '-1');
tabselect = this.messageArea.find(tabselect);
tabselect.addClass('selected');
tabselect.attr('aria-selected', 'true');
tabselect.attr('tabindex', '0');
};
/**
* Change to the inactive tab.
*
* @param {event} e The javascript event
* @param {object} data The additional event data
* @private
*/
Tabs.prototype._toggleTabs = function(e, data) {
var activeTab = this.messageArea.find(SELECTORS.ACTIVECONTACTSTAB);
if (activeTab.is(SELECTORS.VIEWCONVERSATIONS)) {
this._viewContacts();
} else {
this._viewConversations();
}
this.messageArea.find(SELECTORS.ACTIVECONTACTSTAB).focus();
e.preventDefault();
e.stopPropagation();
data.originalEvent.preventDefault();
data.originalEvent.stopPropagation();
};
return Tabs;
});

View File

@ -1,125 +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/>.
/**
* Controls the message preference page.
*
* @module core_message/message_preferences
* @class message_preferences
* @package message
* @copyright 2016 Ryan Wyllie <ryan@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
define(['jquery', 'core/ajax', 'core/notification',
'core_message/message_notification_preference', 'core/custom_interaction_events'],
function($, Ajax, Notification, MessageNotificationPreference, CustomEvents) {
var SELECTORS = {
PREFERENCE: '[data-state]',
PREFERENCES_CONTAINER: '[data-region="preferences-container"]',
CONTACTABLE_PRIVACY_CONTAINER: '[data-region="privacy-setting-container"]',
};
/**
* Constructor for the MessagePreferences.
*
* @param {object} element The root element for the message preferences
*/
var MessagePreferences = function(element) {
this.root = $(element);
this.userId = this.root.find(SELECTORS.PREFERENCES_CONTAINER).attr('data-user-id');
this.registerEventListeners();
};
/**
* Check if the preferences have been disabled on this page.
*
* @method preferencesDisabled
* @return {bool}
*/
MessagePreferences.prototype.preferencesDisabled = function() {
return this.root.find(SELECTORS.PREFERENCES_CONTAINER).hasClass('disabled');
};
/**
* Update the contactable privacy user preference in the DOM and
* send a request to update on the server.
*
* @return {Promise}
* @method saveContactablePrivacySetting
*/
MessagePreferences.prototype.saveContactablePrivacySetting = function() {
var container = this.root.find(SELECTORS.CONTACTABLE_PRIVACY_CONTAINER);
var value = $("input[type='radio']:checked").val();
if (container.hasClass('loading')) {
return $.Deferred().resolve();
}
container.addClass('loading');
var request = {
methodname: 'core_user_update_user_preferences',
args: {
userid: this.userId,
preferences: [
{
type: container.attr('data-preference-key'),
value: value,
}
]
}
};
return Ajax.call([request])[0]
.fail(Notification.exception)
.always(function() {
container.removeClass('loading');
});
};
/**
* Create all of the event listeners for the message preferences page.
*
* @method registerEventListeners
*/
MessagePreferences.prototype.registerEventListeners = function() {
CustomEvents.define(this.root, [
CustomEvents.events.activate
]);
this.root.on('change', function(e) {
// Add listener for privacy setting radio buttons change.
if (e.target.name == 'message_blocknoncontacts') {
this.saveContactablePrivacySetting();
} else {
// Add listener for processor preferences.
if (!this.preferencesDisabled()) {
var preferencesContainer = $(e.target).closest(SELECTORS.PREFERENCES_CONTAINER);
var preferenceElement = $(e.target).closest(SELECTORS.PREFERENCE);
var messagePreference = new MessageNotificationPreference(preferencesContainer, this.userId);
preferenceElement.addClass('loading');
messagePreference.save().always(function() {
preferenceElement.removeClass('loading');
});
}
}
}.bind(this));
};
return MessagePreferences;
});