diff --git a/message/amd/build/message_drawer_view_conversation.min.js b/message/amd/build/message_drawer_view_conversation.min.js index 67374e6b6ad..63ce8d317f5 100644 --- a/message/amd/build/message_drawer_view_conversation.min.js +++ b/message/amd/build/message_drawer_view_conversation.min.js @@ -1 +1 @@ -define(["jquery","core/auto_rows","core/backoff_timer","core/custom_interaction_events","core/notification","core/pubsub","core/str","core_message/message_repository","core_message/message_drawer_events","core_message/message_drawer_view_conversation_constants","core_message/message_drawer_view_conversation_patcher","core_message/message_drawer_view_conversation_renderer","core_message/message_drawer_view_conversation_state_manager","core_message/message_drawer_router","core_message/message_drawer_routes"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={},q=null,r=!1,s=0,t=null,u=!0,v=!1,w=null,x=[],y=j.NEWEST_MESSAGES_FIRST,z=j.LOAD_MESSAGE_LIMIT,A=j.INITIAL_NEW_MESSAGE_POLL_TIMEOUT,B=j.SELECTORS,C=j.CONVERSATION_TYPES,D=function(){if(!q||q.type==C.PUBLIC)return null;var a=q.loggedInUserId;if(q.type==C.SELF)return a;var b=Object.keys(q.members).filter(function(b){return a!=b});return b.length?b[0]:null},E=function(a){return Object.keys(p).reduce(function(b,c){if(!b){var d=p[c].state;d.type!=C.PUBLIC&&a in d.members&&(b=d.id)}return b},null)},F=function(a){return{id:parseInt(a.attr("data-user-id"),10),fullname:null,profileimageurl:null,profileimageurlsmall:null,isonline:null,showonlinestatus:null,isblocked:null,iscontact:null,isdeleted:null,canmessage:null,requirescontact:null,contactrequests:[]}},G=function(){return s},H=function(a){s=a,p[q.id].messagesOffset=a},I=function(){return r},J=function(a){r=a,p[q.id].loadedAllMessages=a},K=function(a){return a.find(B.MESSAGES_CONTAINER)},L=function(b){return{id:b.id,name:b.name,subname:b.subname,imageUrl:b.imageUrl,isFavourite:b.isFavourite,isMuted:b.isMuted,type:b.type,totalMemberCount:b.totalMemberCount,loggedInUserId:b.loggedInUserId,messages:b.messages.map(function(b){return a.extend({},b)}),members:Object.keys(b.members).map(function(c){var d=a.extend({},b.members[c]);return d.contactrequests=b.members[c].contactrequests.map(function(b){return a.extend({},b)}),d})}},M=function(a,b){var c=a.id,d=c==b?C.SELF:C.PRIVATE,f=m.setLoadingMembers(q,!0);return f=m.setLoadingMessages(f,!0),w(f).then(function(){return h.getMemberInfo(c,[b],!0,!0)}).then(function(a){if(a.length)return a[0];throw new Error("Unable to load other user profile")}).then(function(b){var c=d==C.SELF?[b]:[b,a],e=m.addMembers(q,c);return e=m.setLoadingMembers(e,!1),e=m.setLoadingMessages(e,!1),e=m.setName(e,b.fullname),e=m.setType(e,d),e=m.setImageUrl(e,b.profileimageurl),e=m.setTotalMemberCount(e,c.length),w(e).then(function(){return b})})["catch"](function(a){var b=m.setLoadingMembers(q,!1);w(b),e.exception(a)})},N=function(a,b){var c=null;if(a.type==C.PRIVATE){var d=a.members.filter(function(a){return a.id!=b});c=d.length?d[0]:null}else a.type==C.SELF&&(c=a.members[0]);var e=a.name,f=a.imageurl;a.type!=C.PUBLIC&&(e=e||c?c.fullname:"",f=f||c?c.profileimageurl:"");var g=m.addMembers(q,a.members);return g=m.setName(g,e),g=m.setSubname(g,a.subname),g=m.setType(g,a.type),g=m.setImageUrl(g,f),g=m.setTotalMemberCount(g,a.membercount),g=m.setIsFavourite(g,a.isfavourite),g=m.setIsMuted(g,a.ismuted),g=m.addMessages(g,a.messages),g=m.setCanDeleteMessagesForAllUsers(g,a.candeletemessagesforallusers)},O=function(a,b,c,d,f){var g=b.id,i=m.setLoadingMembers(q,!0);return i=m.setLoadingMessages(i,!0),w(i).then(function(){return h.getConversation(g,a,!0,!0,0,0,c+1,d,f)}).then(function(a){return a.messages.length>c?a.messages=a.messages.slice(1):J(!0),H(d+c),a}).then(function(a){var c=a.members.filter(function(a){return a.id==b.id});c.length<1&&(a.members=a.members.concat([b]));var d=N(a,b.id);return d=m.setLoadingMembers(d,!1),d=m.setLoadingMessages(d,!1),w(d).then(function(){return a})}).then(function(){return S(a)})["catch"](function(a){var b=m.setLoadingMembers(q,!1);b=m.setLoadingMessages(b,!1),w(b),e.exception(a)})},P=function(a,b,c,d){var f=a.members.filter(function(a){return a.id==b.id});f.length<1&&(a.members=a.members.concat([b]));var g=N(a,b.id);g=m.setLoadingMembers(g,!1),g=m.setLoadingMessages(g,!0);var h=a.messages.length;return w(g).then(function(){if(hb?a.messages=a.messages.slice(0,-1):J(!0),a):a}).then(function(a){var b=a.members.filter(function(a){return!(a.id in q.members)}),c=m.addMembers(q,b);return c=m.addMessages(c,a.messages),c=m.setLoadingMessages(c,!1),w(c).then(function(){return a})})["catch"](function(a){var b=m.setLoadingMessages(q,!1);throw w(b),a})},R=function(b,c){return function(){var d=q.messages,e=d.length?d[d.length-1]:null;if(e&&!u&&!v){for(var g=[],h=d.length-1;h>=0;h--){var j=d[h];if(j.timeCreated!==e.timeCreated)break;g.push(j.id)}return Q(b,0,0,c,g,e.timeCreated).then(function(a){if(a.messages.length){t.restart();var c=L(q);return f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,c),S(b)}return a})}return a.Deferred().resolve().promise()}},S=function(a){var b=q.loggedInUserId;return h.markAllConversationMessagesAsRead(b,a).then(function(){var b=m.markMessagesAsRead(q,q.messages);return f.publish(i.CONVERSATION_READ,a),w(b)})},T=function(a){return ha(a).then(function(){var b=m.addPendingBlockUsersById(q,[a]);return w(b)})},U=function(a){var b=m.setLoadingConfirmAction(q,!0);return w(b).then(function(){return h.blockUser(q.loggedInUserId,a)}).then(function(b){var c=m.addMembers(q,[b]);return c=m.removePendingBlockUsersById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_BLOCKED,a),w(c)})},V=function(a){return ha(a).then(function(){var b=m.addPendingUnblockUsersById(q,[a]);return w(b)})},W=function(a){var b=m.setLoadingConfirmAction(q,!0);return w(b).then(function(){return h.unblockUser(q.loggedInUserId,a)}).then(function(b){var c=m.addMembers(q,[b]);return c=m.removePendingUnblockUsersById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_UNBLOCKED,a),w(c)})},X=function(a){return ha(a).then(function(){var b=m.addPendingRemoveContactsById(q,[a]);return w(b)})},Y=function(a){var b=m.setLoadingConfirmAction(q,!0);return w(b).then(function(){return h.deleteContacts(q.loggedInUserId,[a])}).then(function(b){var c=m.addMembers(q,b);return c=m.removePendingRemoveContactsById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_REMOVED,a),w(c)})},Z=function(a){return ha(a).then(function(){var b=m.addPendingAddContactsById(q,[a]);return w(b)})},$=function(a){var b=m.setLoadingConfirmAction(q,!0);return w(b).then(function(){return h.createContactRequest(q.loggedInUserId,a)}).then(function(a){if(!a.request)throw new Error(a.warnings[0].message);return a.request}).then(function(b){var c=m.removePendingAddContactsById(q,[a]);return c=m.addContactRequests(c,[b]),c=m.setLoadingConfirmAction(c,!1),w(c)})},_=function(){var a=q.loggedInUserId,b=q.id;return h.setFavouriteConversations(a,[b]).then(function(){var a=m.setIsFavourite(q,!0);return w(a)}).then(function(){return f.publish(i.CONVERSATION_SET_FAVOURITE,L(q))})},aa=function(){var a=q.loggedInUserId,b=q.id;return h.unsetFavouriteConversations(a,[b]).then(function(){var a=m.setIsFavourite(q,!1);return w(a)}).then(function(){return f.publish(i.CONVERSATION_UNSET_FAVOURITE,L(q))})},ba=function(){var a=q.loggedInUserId,b=q.id;return h.setMutedConversations(a,[b]).then(function(){var a=m.setIsMuted(q,!0);return w(a)}).then(function(){return f.publish(i.CONVERSATION_SET_MUTED,L(q))})},ca=function(){var a=q.loggedInUserId,b=q.id;return h.unsetMutedConversations(a,[b]).then(function(){var a=m.setIsMuted(q,!1);return w(a)}).then(function(){return f.publish(i.CONVERSATION_UNSET_MUTED,L(q))})},da=function(a){var b=q.selectedMessageIds;return ha(a).then(function(){var a=m.addPendingDeleteMessagesById(q,b);return w(a)})},ea=function(){var a=q.pendingDeleteMessageIds,b=m.setLoadingConfirmAction(q,!0);return w(b).then(function(){return b.deleteMessagesForAllUsers?h.deleteMessagesForAllUsers(q.loggedInUserId,a):h.deleteMessages(q.loggedInUserId,a)}).then(function(){var b=m.removeMessagesById(q,a);b=m.removePendingDeleteMessagesById(b,a),b=m.removeSelectedMessagesById(b,a),b=m.setLoadingConfirmAction(b,!1),b=m.setDeleteMessagesForAllUsers(b,!1);var c=q.messages[q.messages.length-1],d=b.messages.length?b.messages[b.messages.length-1]:null;if(d&&d.id!=c.id){var e=L(b);f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,e)}else b.messages.length||f.publish(i.CONVERSATION_DELETED,b.id);return w(b)})},fa=function(a){return ha(a).then(function(){var a=m.setPendingDeleteConversation(q,!0);return w(a)})},ga=function(){var a=m.setLoadingConfirmAction(q,!0);return w(a).then(function(){return h.deleteConversation(q.loggedInUserId,q.id)}).then(function(){var a=m.removeMessages(q,q.messages);return a=m.removeSelectedMessagesById(a,q.selectedMessageIds),a=m.setPendingDeleteConversation(a,!1),a=m.setLoadingConfirmAction(a,!1),f.publish(i.CONVERSATION_DELETED,a.id),w(a)})},ha=function(a){var b=q.pendingDeleteMessageIds,c=m.removePendingAddContactsById(q,[a]);return c=m.removePendingRemoveContactsById(c,[a]),c=m.removePendingUnblockUsersById(c,[a]),c=m.removePendingBlockUsersById(c,[a]),c=m.removePendingDeleteMessagesById(c,b),c=m.setPendingDeleteConversation(c,!1),c=m.setDeleteMessagesForAllUsers(c,!1),w(c)},ia=function(a){var b=q.loggedInUserId,c=q.members[a].contactrequests.filter(function(a){return a.requesteduserid==b}),d=c[0],e=m.setLoadingConfirmAction(q,!0);return w(e).then(function(){return h.acceptContactRequest(a,b)}).then(function(a){var b=m.removeContactRequests(q,[d]);return b=m.addMembers(q,[a]),b=m.setLoadingConfirmAction(b,!1),w(b)}).then(function(){f.publish(i.CONTACT_ADDED,q.members[a]),f.publish(i.CONTACT_REQUEST_ACCEPTED,d)})},ja=function(a){var b=q.loggedInUserId,c=q.members[a].contactrequests.filter(function(a){return a.requesteduserid==b}),d=c[0],e=m.setLoadingConfirmAction(q,!0);return w(e).then(function(){return h.declineContactRequest(a,b)}).then(function(a){var b=m.removeContactRequests(q,[d]);return b=m.addMembers(q,[a]),b=m.setLoadingConfirmAction(b,!1),w(b)}).then(function(){f.publish(i.CONTACT_REQUEST_DECLINED,d)})},ka=function(a,b){v=!0;var c=m.setSendingMessage(q,!0),d=null,g=!1;return w(c).then(function(){if(a||q.type==C.PUBLIC)return h.sendMessageToConversation(a,b);var c=D();return h.sendMessageToUser(c,b).then(function(a){return d=parseInt(a.conversationid,10),g=a.candeletemessagesforallusers,a})}).then(function(a){var b=m.addMessages(q,[a]);b=m.setSendingMessage(b,!1);var c=L(b);return b.id||(b=m.setId(b,d),c.id=d,Aa(d),f.publish(i.CONVERSATION_CREATED,c),b=m.setCanDeleteMessagesForAllUsers(b,g)),w(b).then(function(){v=!1,f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,c)})})["catch"](function(a){v=!1;var b=m.setSendingMessage(q,!1);w(b),e.exception(a)})},la=function(a){var b=q;return b=q.selectedMessageIds.indexOf(a)>-1?m.removeSelectedMessagesById(q,[a]):m.addSelectedMessagesById(q,[a]),w(b)},ma=function(){return ha(D()).then(function(){var a=m.removeSelectedMessagesById(q,q.selectedMessageIds);return w(a)})},na=function(b,c,d,e){var f=function(a){return l.render(b,c,d,a)};if(!e){var g=m.buildInitialState(q.midnight,q.loggedInUserId,q.id),h=k.buildPatch(g,q);f(h)}return x.push(f),function(b){var c=k.buildPatch(q,b),d=x.map(function(a){return a(c)});return a.when.apply(null,d).then(function(){q=b,b.id&&(p[b.id]={state:b,messagesOffset:G(),loadedAllMessages:I()})})}},oa=function(a){return function(b,c){q.loadingConfirmAction||a(D())["catch"](function(a){var b=m.setLoadingConfirmAction(q,!1);w(b),e.exception(a)}),c.originalEvent.preventDefault()}},pa=function(b,c){var d=a(b.target),e=d.closest(B.FOOTER_CONTAINER),f=e.find(B.MESSAGE_TEXT_AREA),g=f.val().trim();""!==g&&ka(q.id,g),c.originalEvent.preventDefault()},qa=function(b,c){var d=window.getSelection(),f=a(b.target);if(""==d.toString()&&!f.is("a")){var g=f.closest(B.MESSAGE),h=parseInt(g.attr("data-message-id"),10);la(h)["catch"](e.exception),c.originalEvent.preventDefault()}},ra=function(a,b){ma()["catch"](e.exception),b.originalEvent.preventDefault()},sa=function(a){return function(b,c){var d=D(),e=q.members[d];n.go(a,o.VIEW_CONTACT,e),c.originalEvent.preventDefault()}},ta=function(a,b){_()["catch"](e.exception),b.originalEvent.preventDefault()},ua=function(a,b){aa()["catch"](e.exception),b.originalEvent.preventDefault()},va=function(a,b){ba()["catch"](e.exception),b.originalEvent.preventDefault()},wa=function(a,b){ca()["catch"](e.exception),b.originalEvent.preventDefault()},xa=function(b){var c=a(b.target).prop("checked"),d=m.setDeleteMessagesForAllUsers(q,c);w(d)},ya=function(a){return function(b,c){n.go(a,o.VIEW_GROUP_INFO,{id:q.id,name:q.name,subname:q.subname,imageUrl:q.imageUrl,totalMemberCount:q.totalMemberCount},q.loggedInUserId),c.originalEvent.preventDefault()}},za=function(a,c,g,h){var j=!1,k=K(g),l=[[B.ACTION_REQUEST_BLOCK,oa(T)],[B.ACTION_REQUEST_UNBLOCK,oa(V)],[B.ACTION_REQUEST_ADD_CONTACT,oa(Z)],[B.ACTION_REQUEST_REMOVE_CONTACT,oa(X)],[B.ACTION_REQUEST_DELETE_CONVERSATION,oa(fa)],[B.ACTION_CANCEL_EDIT_MODE,ra],[B.ACTION_VIEW_CONTACT,sa(a)],[B.ACTION_VIEW_GROUP_INFO,ya(a)],[B.ACTION_CONFIRM_FAVOURITE,ta],[B.ACTION_CONFIRM_MUTE,va],[B.ACTION_CONFIRM_UNFAVOURITE,ua],[B.ACTION_CONFIRM_UNMUTE,wa]],n=[[B.ACTION_CANCEL_CONFIRM,oa(ha)],[B.ACTION_CONFIRM_BLOCK,oa(U)],[B.ACTION_CONFIRM_UNBLOCK,oa(W)],[B.ACTION_CONFIRM_ADD_CONTACT,oa($)],[B.ACTION_CONFIRM_REMOVE_CONTACT,oa(Y)],[B.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES,oa(ea)],[B.ACTION_CONFIRM_DELETE_CONVERSATION,oa(ga)],[B.ACTION_REQUEST_ADD_CONTACT,oa(Z)],[B.ACTION_ACCEPT_CONTACT_REQUEST,oa(ia)],[B.ACTION_DECLINE_CONTACT_REQUEST,oa(ja)],[B.MESSAGE,qa],[B.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE,xa]],p=[[B.SEND_MESSAGE_BUTTON,pa],[B.ACTION_REQUEST_DELETE_SELECTED_MESSAGES,oa(da)],[B.ACTION_REQUEST_ADD_CONTACT,oa(Z)],[B.ACTION_REQUEST_UNBLOCK,oa(V)]];b.init(h),d.define(c,[d.events.activate]),d.define(g,[d.events.activate]),d.define(h,[d.events.activate,d.events.enter]),d.define(k,[d.events.scrollTop,d.events.scrollLock]),k.on(d.events.scrollTop,function(a,b){var c=Object.keys(q.members).length>1;if(!u&&!j&&!I()&&c){j=!0;var d=m.setLoadingMessages(q,!0);w(d).then(function(){return Q(q.id,z,G(),y,[])}).then(function(){j=!1,H(G()+z)})["catch"](function(a){j=!1,e.exception(a)})}b.originalEvent.preventDefault()}),l.forEach(function(a){var b=a[0],e=a[1];c.on(d.events.activate,b,e)}),n.forEach(function(a){var b=a[0],c=a[1];g.on(d.events.activate,b,c)}),p.forEach(function(a){var b=a[0],c=a[1];h.on(d.events.activate,b,c)}),h.on(d.events.enter,B.MESSAGE_TEXT_AREA,function(a,b){var c=h.attr("data-enter-to-send");c&&"false"!=c&&"0"!=c&&pa(a,b)}),f.subscribe(i.ROUTE_CHANGED,function(a){t&&a.route!=o.VIEW_CONVERSATION&&t.stop()})},Aa=function(a){t&&t.stop(),t=new c(R(a,y),function(a){return a?2*a:A}),t.start()},Ba=function(a,b,c){var d=c.id,e=parseInt(a.attr("data-midnight"),10),f=m.buildInitialState(e,d,b);return q||(q=f),t&&t.stop(),w(f)},Ca=function(a,b,c){return Ba(a,null,b).then(function(){return b.id!=c?h.getConversationBetweenUsers(b.id,c,!0,!0,0,0,z,0,y):h.getSelfConversation(b.id,z,0,y)}).then(function(c){return Ea(a,c,b)})["catch"](function(){return M(b,c)})},Da=function(a,b,c){var d=null;return b in p&&(d=p[b]),Ba(a,b,c).then(function(){if(d){var a=d.state;return a=m.setLoadingMessages(a,!1),a=m.setLoadingMembers(a,!1),H(d.messagesOffset),J(d.loadedAllMessages),w(a)}return O(b,c,z,0,y)}).then(function(){return Aa(b)})},Ea=function(a,b,c){var d=null;return b.id in p&&(d=p[b.id]),Ba(a,b.id,c).then(function(){if(d){var a=d.state;return a=m.setLoadingMessages(a,!1),a=m.setLoadingMembers(a,!1),H(d.messagesOffset),J(d.loadedAllMessages),w(a)}return P(b,c,z,y)}).then(function(){return Aa(b.id)})},Fa=function(b,c,d,f,g,h,i){var k=null,l=null;g&&null!==g&&"object"==typeof g?(k=g,l=parseInt(k.id,10)):(k=null,l=parseInt(g,10),l=isNaN(l)?null:l),!l&&h&&i&&(l=E(i));var m=!q||q.id!=l||i&&i!=D();if(d.attr("data-init")||(w=na(c,d,f,m),za(b,c,d,f),d.attr("data-init",!0)),m){u=!0;var n=null,o=F(d);return n=k?Ea(d,k,o,i):l?Da(d,l,o,i):Ca(d,o,i),n.then(function(){u=!1,c.find(j.SELECTORS.CAN_RECEIVE_FOCUS).first().focus()})["catch"](function(a){u=!1,e.exception(a)})}if(Aa(l),q.type==C.PRIVATE&&h){var p=D();switch(h){case"block":return T(p);case"unblock":return V(p);case"add-contact":return Z(p);case"remove-contact":return X(p)}}return a.Deferred().resolve().promise()},Ga=function(){return g.get_string("messagedrawerviewconversation","core_message",q.name)};return{show:Fa,description:Ga}}); \ No newline at end of file +define(["jquery","core/auto_rows","core/backoff_timer","core/custom_interaction_events","core/notification","core/pubsub","core/str","core_message/message_repository","core_message/message_drawer_events","core_message/message_drawer_view_conversation_constants","core_message/message_drawer_view_conversation_patcher","core_message/message_drawer_view_conversation_renderer","core_message/message_drawer_view_conversation_state_manager","core_message/message_drawer_router","core_message/message_drawer_routes"],function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o){var p={},q=null,r=!1,s=0,t=null,u=!1,v=[],w=!0,x=!1,y=null,z=[],A=j.NEWEST_MESSAGES_FIRST,B=j.LOAD_MESSAGE_LIMIT,C=j.INITIAL_NEW_MESSAGE_POLL_TIMEOUT,D=j.SELECTORS,E=j.CONVERSATION_TYPES,F=function(){if(!q||q.type==E.PUBLIC)return null;var a=q.loggedInUserId;if(q.type==E.SELF)return a;var b=Object.keys(q.members).filter(function(b){return a!=b});return b.length?b[0]:null},G=function(a){return Object.keys(p).reduce(function(b,c){if(!b){var d=p[c].state;d.type!=E.PUBLIC&&a in d.members&&(b=d.id)}return b},null)},H=function(a){return{id:parseInt(a.attr("data-user-id"),10),fullname:null,profileimageurl:null,profileimageurlsmall:null,isonline:null,showonlinestatus:null,isblocked:null,iscontact:null,isdeleted:null,canmessage:null,requirescontact:null,contactrequests:[]}},I=function(){return s},J=function(a){s=a,p[q.id].messagesOffset=a},K=function(){return r},L=function(a){r=a,p[q.id].loadedAllMessages=a},M=function(a){return a.find(D.MESSAGES_CONTAINER)},N=function(b){return{id:b.id,name:b.name,subname:b.subname,imageUrl:b.imageUrl,isFavourite:b.isFavourite,isMuted:b.isMuted,type:b.type,totalMemberCount:b.totalMemberCount,loggedInUserId:b.loggedInUserId,messages:b.messages.map(function(b){return a.extend({},b)}),members:Object.keys(b.members).map(function(c){var d=a.extend({},b.members[c]);return d.contactrequests=b.members[c].contactrequests.map(function(b){return a.extend({},b)}),d})}},O=function(a,b){var c=a.id,d=c==b?E.SELF:E.PRIVATE,f=m.setLoadingMembers(q,!0);return f=m.setLoadingMessages(f,!0),y(f),h.getMemberInfo(c,[b],!0,!0).then(function(a){if(a.length)return a[0];throw new Error("Unable to load other user profile")}).then(function(b){var c=d==E.SELF?[b]:[b,a],e=m.addMembers(q,c);return e=m.setLoadingMembers(e,!1),e=m.setLoadingMessages(e,!1),e=m.setName(e,b.fullname),e=m.setType(e,d),e=m.setImageUrl(e,b.profileimageurl),e=m.setTotalMemberCount(e,c.length),y(e),b})["catch"](function(a){var b=m.setLoadingMembers(q,!1);y(b),e.exception(a)})},P=function(a,b){var c=null;if(a.type==E.PRIVATE){var d=a.members.filter(function(a){return a.id!=b});c=d.length?d[0]:null}else a.type==E.SELF&&(c=a.members[0]);var e=a.name,f=a.imageurl;a.type!=E.PUBLIC&&(e=e||c?c.fullname:"",f=f||c?c.profileimageurl:"");var g=m.addMembers(q,a.members);return g=m.setName(g,e),g=m.setSubname(g,a.subname),g=m.setType(g,a.type),g=m.setImageUrl(g,f),g=m.setTotalMemberCount(g,a.membercount),g=m.setIsFavourite(g,a.isfavourite),g=m.setIsMuted(g,a.ismuted),g=m.addMessages(g,a.messages),g=m.setCanDeleteMessagesForAllUsers(g,a.candeletemessagesforallusers)},Q=function(a,b,c,d,f){var g=b.id,i=m.setLoadingMembers(q,!0);return i=m.setLoadingMessages(i,!0),y(i),h.getConversation(g,a,!0,!0,0,0,c+1,d,f).then(function(a){return a.messages.length>c?a.messages=a.messages.slice(1):L(!0),J(d+c),a}).then(function(a){var c=a.members.filter(function(a){return a.id==b.id});c.length<1&&(a.members=a.members.concat([b]));var d=P(a,b.id);return d=m.setLoadingMembers(d,!1),d=m.setLoadingMessages(d,!1),y(d).then(function(){return a})}).then(function(){return U(a)})["catch"](function(a){var b=m.setLoadingMembers(q,!1);b=m.setLoadingMessages(b,!1),y(b),e.exception(a)})},R=function(a,b,c,d){var f=a.members.filter(function(a){return a.id==b.id});f.length<1&&(a.members=a.members.concat([b]));var g=a.messages.length,h=g>=c,i=P(a,b.id);i=m.setLoadingMembers(i,!1),i=m.setLoadingMessages(i,!h);var j=y(i);return j.then(function(){return h?{messages:a.messages}:S(a.id,c,g,d,[])}).then(function(){var a=q.messages;return J(a.length),U(q.id),a})["catch"](e.exception)},S=function(a,b,c,d,e,f){return h.getMessages(q.loggedInUserId,a,b?b+1:b,c,d,f).then(function(a){return a.messages.length&&e.length&&(a.messages=a.messages.filter(function(a){return e.indexOf(parseInt(a.id,10))<0})),a}).then(function(a){return b?(a.messages.length>b?a.messages=a.messages.slice(0,-1):L(!0),a):a}).then(function(a){var b=a.members.filter(function(a){return!(a.id in q.members)}),c=m.addMembers(q,b);return c=m.addMessages(c,a.messages),c=m.setLoadingMessages(c,!1),y(c).then(function(){return a})})["catch"](function(a){var b=m.setLoadingMessages(q,!1);throw y(b),a})},T=function(b,c){return function(){var d=q.messages,e=d.length?d[d.length-1]:null;if(e&&!w&&!x){for(var g=[],h=d.length-1;h>=0;h--){var j=d[h];if(j.timeCreated!==e.timeCreated)break;g.push(j.id)}return S(b,0,0,c,g,e.timeCreated).then(function(a){if(a.messages.length){t.restart();var c=N(q);return f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,c),U(b)}return a})}return a.Deferred().resolve().promise()}},U=function(a){var b=q.loggedInUserId;return h.markAllConversationMessagesAsRead(b,a).then(function(){var b=m.markMessagesAsRead(q,q.messages);return f.publish(i.CONVERSATION_READ,a),y(b)})},V=function(a){ja(a);var b=m.addPendingBlockUsersById(q,[a]);y(b)},W=function(a){var b=m.setLoadingConfirmAction(q,!0);return y(b),h.blockUser(q.loggedInUserId,a).then(function(b){var c=m.addMembers(q,[b]);return c=m.removePendingBlockUsersById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_BLOCKED,a),y(c)})},X=function(a){ja(a);var b=m.addPendingUnblockUsersById(q,[a]);y(b)},Y=function(a){var b=m.setLoadingConfirmAction(q,!0);return y(b),h.unblockUser(q.loggedInUserId,a).then(function(b){var c=m.addMembers(q,[b]);return c=m.removePendingUnblockUsersById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_UNBLOCKED,a),y(c)})},Z=function(a){ja(a);var b=m.addPendingRemoveContactsById(q,[a]);y(b)},$=function(a){var b=m.setLoadingConfirmAction(q,!0);return y(b),h.deleteContacts(q.loggedInUserId,[a]).then(function(b){var c=m.addMembers(q,b);return c=m.removePendingRemoveContactsById(c,[a]),c=m.setLoadingConfirmAction(c,!1),f.publish(i.CONTACT_REMOVED,a),y(c)})},_=function(a){ja(a);var b=m.addPendingAddContactsById(q,[a]);y(b)},aa=function(a){var b=m.setLoadingConfirmAction(q,!0);return y(b),h.createContactRequest(q.loggedInUserId,a).then(function(a){if(!a.request)throw new Error(a.warnings[0].message);return a.request}).then(function(b){var c=m.removePendingAddContactsById(q,[a]);return c=m.addContactRequests(c,[b]),c=m.setLoadingConfirmAction(c,!1),y(c)})},ba=function(){var a=q.loggedInUserId,b=q.id;return h.setFavouriteConversations(a,[b]).then(function(){var a=m.setIsFavourite(q,!0);return y(a)}).then(function(){return f.publish(i.CONVERSATION_SET_FAVOURITE,N(q))})},ca=function(){var a=q.loggedInUserId,b=q.id;return h.unsetFavouriteConversations(a,[b]).then(function(){var a=m.setIsFavourite(q,!1);return y(a)}).then(function(){return f.publish(i.CONVERSATION_UNSET_FAVOURITE,N(q))})},da=function(){var a=q.loggedInUserId,b=q.id;return h.setMutedConversations(a,[b]).then(function(){var a=m.setIsMuted(q,!0);return y(a)}).then(function(){return f.publish(i.CONVERSATION_SET_MUTED,N(q))})},ea=function(){var a=q.loggedInUserId,b=q.id;return h.unsetMutedConversations(a,[b]).then(function(){var a=m.setIsMuted(q,!1);return y(a)}).then(function(){return f.publish(i.CONVERSATION_UNSET_MUTED,N(q))})},fa=function(a){var b=q.selectedMessageIds;ja(a);var c=m.addPendingDeleteMessagesById(q,b);y(c)},ga=function(){var a=q.pendingDeleteMessageIds,b=m.setLoadingConfirmAction(q,!0);y(b);var c=null;return c=b.deleteMessagesForAllUsers?h.deleteMessagesForAllUsers(q.loggedInUserId,a):h.deleteMessages(q.loggedInUserId,a),c.then(function(){var b=m.removeMessagesById(q,a);b=m.removePendingDeleteMessagesById(b,a),b=m.removeSelectedMessagesById(b,a),b=m.setLoadingConfirmAction(b,!1),b=m.setDeleteMessagesForAllUsers(b,!1);var c=q.messages[q.messages.length-1],d=b.messages.length?b.messages[b.messages.length-1]:null;if(d&&d.id!=c.id){var e=N(b);f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,e)}else b.messages.length||f.publish(i.CONVERSATION_DELETED,b.id);return y(b)})},ha=function(a){ja(a);var b=m.setPendingDeleteConversation(q,!0);y(b)},ia=function(){var a=m.setLoadingConfirmAction(q,!0);return y(a),h.deleteConversation(q.loggedInUserId,q.id).then(function(){var a=m.removeMessages(q,q.messages);return a=m.removeSelectedMessagesById(a,q.selectedMessageIds),a=m.setPendingDeleteConversation(a,!1),a=m.setLoadingConfirmAction(a,!1),f.publish(i.CONVERSATION_DELETED,a.id),y(a)})},ja=function(a){var b=q.pendingDeleteMessageIds,c=m.removePendingAddContactsById(q,[a]);c=m.removePendingRemoveContactsById(c,[a]),c=m.removePendingUnblockUsersById(c,[a]),c=m.removePendingBlockUsersById(c,[a]),c=m.removePendingDeleteMessagesById(c,b),c=m.setPendingDeleteConversation(c,!1),c=m.setDeleteMessagesForAllUsers(c,!1),y(c)},ka=function(a){var b=q.loggedInUserId,c=q.members[a].contactrequests.filter(function(a){return a.requesteduserid==b}),d=c[0],e=m.setLoadingConfirmAction(q,!0);return y(e),h.acceptContactRequest(a,b).then(function(a){var b=m.removeContactRequests(q,[d]);return b=m.addMembers(q,[a]),b=m.setLoadingConfirmAction(b,!1),y(b)}).then(function(){f.publish(i.CONTACT_ADDED,q.members[a]),f.publish(i.CONTACT_REQUEST_ACCEPTED,d)})},la=function(a){var b=q.loggedInUserId,c=q.members[a].contactrequests.filter(function(a){return a.requesteduserid==b}),d=c[0],e=m.setLoadingConfirmAction(q,!0);return y(e),h.declineContactRequest(a,b).then(function(a){var b=m.removeContactRequests(q,[d]);return b=m.addMembers(q,[a]),b=m.setLoadingConfirmAction(b,!1),y(b)}).then(function(){f.publish(i.CONTACT_REQUEST_DECLINED,d)})},ma=function(a,b){x=!0;var c=m.setSendingMessage(q,!0),d=null;y(c);var g=null,j=null;if(a||q.type==E.PUBLIC)g=h.sendMessageToConversation(a,b);else{var k=F();g=h.sendMessageToUser(k,b).then(function(a){return d=parseInt(a.conversationid,10),j=a.candeletemessagesforallusers,a})}g.then(function(a){var b=m.addMessages(q,[a]);b=m.setSendingMessage(b,!1);var c=N(b);b.id||(b=m.setId(b,d),c.id=d,Da(d),f.publish(i.CONVERSATION_CREATED,c),b=m.setCanDeleteMessagesForAllUsers(b,j)),y(b),x=!1,f.publish(i.CONVERSATION_NEW_LAST_MESSAGE,c)})["catch"](function(a){x=!1;var b=m.setSendingMessage(q,!1);y(b),e.exception(a)})},na=function(a){var b=q;b=q.selectedMessageIds.indexOf(a)>-1?m.removeSelectedMessagesById(q,[a]):m.addSelectedMessagesById(q,[a]),y(b)},oa=function(){ja(F());var a=m.removeSelectedMessagesById(q,q.selectedMessageIds);y(a)},pa=function(b,c,d){if(!u&&v.length){u=!0;var f=v.shift(),g=z.map(function(a){return a(f.patch)});a.when.apply(null,g).then(function(){u=!1,f.deferred.resolve(!0),pa(b,c,d)})["catch"](function(a){u=!1,f.deferred.reject(a),e.exception(a)})}},qa=function(b,c,d,e){var f=function(a){return l.render(b,c,d,a)};if(!e){var g=m.buildInitialState(q.midnight,q.loggedInUserId,q.id),h=k.buildPatch(g,q);f(h)}return z.push(f),function(e){var f=k.buildPatch(q,e),g=a.Deferred();return Object.keys(f).length?v.push({patch:f,deferred:g}):g.resolve(!0),q=e,e.id&&(p[e.id]={state:e,messagesOffset:I(),loadedAllMessages:K()}),pa(b,c,d),g.promise()}},ra=function(a){return function(b,c){if(!q.loadingConfirmAction){a(F());var d=m.setLoadingConfirmAction(q,!1);y(d)}c.originalEvent.preventDefault()}},sa=function(b,c){var d=a(b.target),e=d.closest(D.FOOTER_CONTAINER),f=e.find(D.MESSAGE_TEXT_AREA),g=f.val().trim();""!==g&&ma(q.id,g),c.originalEvent.preventDefault()},ta=function(b,c){var d=window.getSelection(),e=a(b.target);if(""==d.toString()&&!e.is("a")){var f=e.closest(D.MESSAGE),g=parseInt(f.attr("data-message-id"),10);na(g),c.originalEvent.preventDefault()}},ua=function(a,b){oa(),b.originalEvent.preventDefault()},va=function(a){return function(b,c){var d=F(),e=q.members[d];n.go(a,o.VIEW_CONTACT,e),c.originalEvent.preventDefault()}},wa=function(a,b){ba()["catch"](e.exception),b.originalEvent.preventDefault()},xa=function(a,b){ca()["catch"](e.exception),b.originalEvent.preventDefault()},ya=function(a,b){da()["catch"](e.exception),b.originalEvent.preventDefault()},za=function(a,b){ea()["catch"](e.exception),b.originalEvent.preventDefault()},Aa=function(b){var c=a(b.target).prop("checked"),d=m.setDeleteMessagesForAllUsers(q,c);y(d)},Ba=function(a){return function(b,c){n.go(a,o.VIEW_GROUP_INFO,{id:q.id,name:q.name,subname:q.subname,imageUrl:q.imageUrl,totalMemberCount:q.totalMemberCount},q.loggedInUserId),c.originalEvent.preventDefault()}},Ca=function(a,c,g,h){var j=!1,k=M(g),l=[[D.ACTION_REQUEST_BLOCK,ra(V)],[D.ACTION_REQUEST_UNBLOCK,ra(X)],[D.ACTION_REQUEST_ADD_CONTACT,ra(_)],[D.ACTION_REQUEST_REMOVE_CONTACT,ra(Z)],[D.ACTION_REQUEST_DELETE_CONVERSATION,ra(ha)],[D.ACTION_CANCEL_EDIT_MODE,ua],[D.ACTION_VIEW_CONTACT,va(a)],[D.ACTION_VIEW_GROUP_INFO,Ba(a)],[D.ACTION_CONFIRM_FAVOURITE,wa],[D.ACTION_CONFIRM_MUTE,ya],[D.ACTION_CONFIRM_UNFAVOURITE,xa],[D.ACTION_CONFIRM_UNMUTE,za]],n=[[D.ACTION_CANCEL_CONFIRM,ra(ja)],[D.ACTION_CONFIRM_BLOCK,ra(W)],[D.ACTION_CONFIRM_UNBLOCK,ra(Y)],[D.ACTION_CONFIRM_ADD_CONTACT,ra(aa)],[D.ACTION_CONFIRM_REMOVE_CONTACT,ra($)],[D.ACTION_CONFIRM_DELETE_SELECTED_MESSAGES,ra(ga)],[D.ACTION_CONFIRM_DELETE_CONVERSATION,ra(ia)],[D.ACTION_REQUEST_ADD_CONTACT,ra(_)],[D.ACTION_ACCEPT_CONTACT_REQUEST,ra(ka)],[D.ACTION_DECLINE_CONTACT_REQUEST,ra(la)],[D.MESSAGE,ta],[D.DELETE_MESSAGES_FOR_ALL_USERS_TOGGLE,Aa]],p=[[D.SEND_MESSAGE_BUTTON,sa],[D.ACTION_REQUEST_DELETE_SELECTED_MESSAGES,ra(fa)],[D.ACTION_REQUEST_ADD_CONTACT,ra(_)],[D.ACTION_REQUEST_UNBLOCK,ra(X)]];b.init(h),d.define(c,[d.events.activate]),d.define(g,[d.events.activate]),d.define(h,[d.events.activate,d.events.enter]),d.define(k,[d.events.scrollTop,d.events.scrollLock]),k.on(d.events.scrollTop,function(a,b){var c=Object.keys(q.members).length>1;if(!w&&!j&&!K()&&c){j=!0;var d=m.setLoadingMessages(q,!0);y(d),S(q.id,B,I(),A,[]).then(function(){j=!1,J(I()+B)})["catch"](function(a){j=!1,e.exception(a)})}b.originalEvent.preventDefault()}),l.forEach(function(a){var b=a[0],e=a[1];c.on(d.events.activate,b,e)}),n.forEach(function(a){var b=a[0],c=a[1];g.on(d.events.activate,b,c)}),p.forEach(function(a){var b=a[0],c=a[1];h.on(d.events.activate,b,c)}),h.on(d.events.enter,D.MESSAGE_TEXT_AREA,function(a,b){var c=h.attr("data-enter-to-send");c&&"false"!=c&&"0"!=c&&sa(a,b)}),f.subscribe(i.ROUTE_CHANGED,function(a){t&&a.route!=o.VIEW_CONVERSATION&&t.stop()})},Da=function(a){t&&t.stop(),t=new c(T(a,A),function(a){return a?2*a:C}),t.start()},Ea=function(a,b,c){w=!0,u=!1,v=[],x=!1;var d=c.id,e=parseInt(a.attr("data-midnight"),10),f=m.buildInitialState(e,d,b);q||(q=f),t&&t.stop(),y(f)},Fa=function(a,b,c){Ea(a,null,b);var d=null;return d=b.id!=c?h.getConversationBetweenUsers(b.id,c,!0,!0,0,0,B,0,A):h.getSelfConversation(b.id,B,0,A),d.then(function(c){return Ha(a,c,b)})["catch"](function(){return O(b,c)})},Ga=function(b,c,d){var e=null;c in p&&(e=p[c]),Ea(b,c,d);var f=a.Deferred().resolve({}).promise();if(e){var g=e.state;g=m.setLoadingMessages(g,!1),g=m.setLoadingMembers(g,!1),J(e.messagesOffset),L(e.loadedAllMessages),y(g)}else f=Q(c,d,B,0,A);return f.then(function(){return Da(c)})},Ha=function(b,c,d){var e=null;c.id in p&&(e=p[c.id]),Ea(b,c.id,d);var f=a.Deferred().resolve({}).promise();if(e){var g=e.state;g=m.setLoadingMessages(g,!1),g=m.setLoadingMembers(g,!1),J(e.messagesOffset),L(e.loadedAllMessages),y(g)}else f=R(c,d,B,A);return f.then(function(){return Da(c.id)})},Ia=function(b,c,d,f,g,h,i){var k=null,l=null;g&&null!==g&&"object"==typeof g?(k=g,l=parseInt(k.id,10)):(k=null,l=parseInt(g,10),l=isNaN(l)?null:l),!l&&h&&i&&(l=G(i));var m=!q||q.id!=l||i&&i!=F();if(d.attr("data-init")||(y=qa(c,d,f,m),Ca(b,c,d,f),d.attr("data-init",!0)),m){var n=null,o=H(d);return n=k?Ha(d,k,o,i):l?Ga(d,l,o,i):Fa(d,o,i),n.then(function(){w=!1,c.find(j.SELECTORS.CAN_RECEIVE_FOCUS).first().focus()})["catch"](function(a){w=!1,e.exception(a)})}if(Da(l),q.type==E.PRIVATE&&h){var p=F();switch(h){case"block":return V(p);case"unblock":return X(p);case"add-contact":return _(p);case"remove-contact":return Z(p)}}return a.Deferred().resolve().promise()},Ja=function(){return g.get_string("messagedrawerviewconversation","core_message",q.name)};return{show:Ia,description:Ja}}); \ No newline at end of file diff --git a/message/amd/src/message_drawer_view_conversation.js b/message/amd/src/message_drawer_view_conversation.js index e2ca7e58647..4c98b0583f7 100644 --- a/message/amd/src/message_drawer_view_conversation.js +++ b/message/amd/src/message_drawer_view_conversation.js @@ -97,11 +97,13 @@ function( var loadedAllMessages = false; var messagesOffset = 0; var newMessagesPollTimer = null; + var isRendering = false; + var renderBuffer = []; // If the UI is currently resetting. var isResetting = true; // If the UI is currently sending a message. var isSendingMessage = false; - // This is the render function which will be generated when this module is + // These functions which will be generated when this module is // first called. See generateRenderFunction for details. var render = null; // The list of renderers that have been registered to render @@ -279,10 +281,9 @@ function( var conversationType = loggedInUserId == otherUserId ? CONVERSATION_TYPES.SELF : CONVERSATION_TYPES.PRIVATE; var newState = StateManager.setLoadingMembers(viewState, true); newState = StateManager.setLoadingMessages(newState, true); - return render(newState) - .then(function() { - return Repository.getMemberInfo(loggedInUserId, [otherUserId], true, true); - }) + render(newState); + + return Repository.getMemberInfo(loggedInUserId, [otherUserId], true, true) .then(function(profiles) { if (profiles.length) { return profiles[0]; @@ -301,10 +302,8 @@ function( newState = StateManager.setType(newState, conversationType); newState = StateManager.setImageUrl(newState, profile.profileimageurl); newState = StateManager.setTotalMemberCount(newState, members.length); - return render(newState) - .then(function() { - return profile; - }); + render(newState); + return profile; }) .catch(function(error) { var newState = StateManager.setLoadingMembers(viewState, false); @@ -374,20 +373,19 @@ function( var loggedInUserId = loggedInUserProfile.id; var newState = StateManager.setLoadingMembers(viewState, true); newState = StateManager.setLoadingMessages(newState, true); - return render(newState) - .then(function() { - return Repository.getConversation( - loggedInUserId, - conversationId, - true, - true, - 0, - 0, - messageLimit + 1, - messageOffset, - newestFirst - ); - }) + render(newState); + + return Repository.getConversation( + loggedInUserId, + conversationId, + true, + true, + 0, + 0, + messageLimit + 1, + messageOffset, + newestFirst + ) .then(function(conversation) { if (conversation.messages.length > messageLimit) { conversation.messages = conversation.messages.slice(1); @@ -450,37 +448,30 @@ function( conversation.members = conversation.members.concat([loggedInUserProfile]); } + var messageCount = conversation.messages.length; + var hasLoadedEnoughMessages = messageCount >= messageLimit; var newState = updateStateFromConversation(conversation, loggedInUserProfile.id); newState = StateManager.setLoadingMembers(newState, false); - newState = StateManager.setLoadingMessages(newState, true); - var messageCount = conversation.messages.length; - return render(newState) - .then(function() { - if (messageCount < messageLimit) { + newState = StateManager.setLoadingMessages(newState, !hasLoadedEnoughMessages); + var renderPromise = render(newState); + + return renderPromise.then(function() { + if (!hasLoadedEnoughMessages) { // We haven't got enough messages so let's load some more. - return loadMessages(conversation.id, messageLimit, messageCount, newestFirst, []) - .then(function(result) { - // Give the list of messages to the next handler. - return result.messages; - }); + return loadMessages(conversation.id, messageLimit, messageCount, newestFirst, []); } else { // We've got enough messages. No need to load any more for now. - var newState = StateManager.setLoadingMessages(viewState, false); - return render(newState) - .then(function() { - // Give the list of messages to the next handler. - return conversation.messages; - }); + return {messages: conversation.messages}; } }) - .then(function(messages) { + .then(function() { + var messages = viewState.messages; // Update the offset to reflect the number of messages we've loaded. setMessagesOffset(messages.length); + markConversationAsRead(viewState.id); + return messages; }) - .then(function() { - return markConversationAsRead(conversation.id); - }) .catch(Notification.exception); }; @@ -627,14 +618,12 @@ function( * Tell the statemanager there is request to block a user and run the renderer * to show the block user dialogue. * - * @param {Number} userId User id. - * @return {Promise} Renderer promise. + * @param {Number} userId User id. */ var requestBlockUser = function(userId) { - return cancelRequest(userId).then(function() { - var newState = StateManager.addPendingBlockUsersById(viewState, [userId]); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.addPendingBlockUsersById(viewState, [userId]); + render(newState); }; /** @@ -646,10 +635,9 @@ function( */ var blockUser = function(userId) { var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.blockUser(viewState.loggedInUserId, userId); - }) + render(newState); + + return Repository.blockUser(viewState.loggedInUserId, userId) .then(function(profile) { var newState = StateManager.addMembers(viewState, [profile]); newState = StateManager.removePendingBlockUsersById(newState, [userId]); @@ -663,14 +651,12 @@ function( * Tell the statemanager there is a request to unblock a user and run the renderer * to show the unblock user dialogue. * - * @param {Number} userId User id of user to unblock. - * @return {Promise} Renderer promise. + * @param {Number} userId User id of user to unblock. */ var requestUnblockUser = function(userId) { - return cancelRequest(userId).then(function() { - var newState = StateManager.addPendingUnblockUsersById(viewState, [userId]); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.addPendingUnblockUsersById(viewState, [userId]); + render(newState); }; /** @@ -682,10 +668,9 @@ function( */ var unblockUser = function(userId) { var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.unblockUser(viewState.loggedInUserId, userId); - }) + render(newState); + + return Repository.unblockUser(viewState.loggedInUserId, userId) .then(function(profile) { var newState = StateManager.addMembers(viewState, [profile]); newState = StateManager.removePendingUnblockUsersById(newState, [userId]); @@ -699,14 +684,12 @@ function( * Tell the statemanager there is a request to remove a user from the contact list * and run the renderer to show the remove user from contacts dialogue. * - * @param {Number} userId User id of user to remove from contacts. - * @return {Promise} Renderer promise. + * @param {Number} userId User id of user to remove from contacts. */ var requestRemoveContact = function(userId) { - return cancelRequest(userId).then(function() { - var newState = StateManager.addPendingRemoveContactsById(viewState, [userId]); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.addPendingRemoveContactsById(viewState, [userId]); + render(newState); }; /** @@ -718,10 +701,9 @@ function( */ var removeContact = function(userId) { var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.deleteContacts(viewState.loggedInUserId, [userId]); - }) + render(newState); + + return Repository.deleteContacts(viewState.loggedInUserId, [userId]) .then(function(profiles) { var newState = StateManager.addMembers(viewState, profiles); newState = StateManager.removePendingRemoveContactsById(newState, [userId]); @@ -735,14 +717,12 @@ function( * Tell the statemanager there is a request to add a user to the contact list * and run the renderer to show the add user to contacts dialogue. * - * @param {Number} userId User id of user to add to contacts. - * @return {Promise} Renderer promise. + * @param {Number} userId User id of user to add to contacts. */ var requestAddContact = function(userId) { - return cancelRequest(userId).then(function() { - var newState = StateManager.addPendingAddContactsById(viewState, [userId]); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.addPendingAddContactsById(viewState, [userId]); + render(newState); }; /** @@ -754,10 +734,9 @@ function( */ var addContact = function(userId) { var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.createContactRequest(viewState.loggedInUserId, userId); - }) + render(newState); + + return Repository.createContactRequest(viewState.loggedInUserId, userId) .then(function(response) { if (!response.request) { throw new Error(response.warnings[0].message); @@ -865,15 +844,13 @@ function( * Tell the statemanager there is a request to delete the selected messages * and run the renderer to show confirm delete messages dialogue. * - * @param {Number} userId User id. - * @return {Promise} Renderer promise. + * @param {Number} userId User id. */ var requestDeleteSelectedMessages = function(userId) { var selectedMessageIds = viewState.selectedMessageIds; - return cancelRequest(userId).then(function() { - var newState = StateManager.addPendingDeleteMessagesById(viewState, selectedMessageIds); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.addPendingDeleteMessagesById(viewState, selectedMessageIds); + render(newState); }; /** @@ -885,15 +862,18 @@ function( var deleteSelectedMessages = function() { var messageIds = viewState.pendingDeleteMessageIds; var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - if (newState.deleteMessagesForAllUsers) { - return Repository.deleteMessagesForAllUsers(viewState.loggedInUserId, messageIds); - } - return Repository.deleteMessages(viewState.loggedInUserId, messageIds); - }) - .then(function() { + render(newState); + + var deleteMessagesPromise = null; + + if (newState.deleteMessagesForAllUsers) { + deleteMessagesPromise = Repository.deleteMessagesForAllUsers(viewState.loggedInUserId, messageIds); + } else { + deleteMessagesPromise = Repository.deleteMessages(viewState.loggedInUserId, messageIds); + } + + return deleteMessagesPromise.then(function() { var newState = StateManager.removeMessagesById(viewState, messageIds); newState = StateManager.removePendingDeleteMessagesById(newState, messageIds); newState = StateManager.removeSelectedMessagesById(newState, messageIds); @@ -918,14 +898,12 @@ function( * Tell the statemanager there is a request to delete a conversation * and run the renderer to show confirm delete conversation dialogue. * - * @param {Number} userId User id of other user. - * @return {Promise} Renderer promise. + * @param {Number} userId User id of other user. */ var requestDeleteConversation = function(userId) { - return cancelRequest(userId).then(function() { - var newState = StateManager.setPendingDeleteConversation(viewState, true); - return render(newState); - }); + cancelRequest(userId); + var newState = StateManager.setPendingDeleteConversation(viewState, true); + render(newState); }; /** @@ -936,10 +914,9 @@ function( */ var deleteConversation = function() { var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.deleteConversation(viewState.loggedInUserId, viewState.id); - }) + render(newState); + + return Repository.deleteConversation(viewState.loggedInUserId, viewState.id) .then(function() { var newState = StateManager.removeMessages(viewState, viewState.messages); newState = StateManager.removeSelectedMessagesById(newState, viewState.selectedMessageIds); @@ -955,7 +932,6 @@ function( * Tell the statemanager to cancel all pending actions. * * @param {Number} userId User id. - * @return {Promise} Renderer promise. */ var cancelRequest = function(userId) { var pendingDeleteMessageIds = viewState.pendingDeleteMessageIds; @@ -966,7 +942,7 @@ function( newState = StateManager.removePendingDeleteMessagesById(newState, pendingDeleteMessageIds); newState = StateManager.setPendingDeleteConversation(newState, false); newState = StateManager.setDeleteMessagesForAllUsers(newState, false); - return render(newState); + render(newState); }; /** @@ -984,10 +960,9 @@ function( }); var request = requests[0]; var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.acceptContactRequest(userId, loggedInUserId); - }) + render(newState); + + return Repository.acceptContactRequest(userId, loggedInUserId) .then(function(profile) { var newState = StateManager.removeContactRequests(viewState, [request]); newState = StateManager.addMembers(viewState, [profile]); @@ -1016,10 +991,9 @@ function( }); var request = requests[0]; var newState = StateManager.setLoadingConfirmAction(viewState, true); - return render(newState) - .then(function() { - return Repository.declineContactRequest(userId, loggedInUserId); - }) + render(newState); + + return Repository.declineContactRequest(userId, loggedInUserId) .then(function(profile) { var newState = StateManager.removeContactRequests(viewState, [request]); newState = StateManager.addMembers(viewState, [profile]); @@ -1044,24 +1018,26 @@ function( isSendingMessage = true; var newState = StateManager.setSendingMessage(viewState, true); var newConversationId = null; - var newCanDeleteMessagesForAllUsers = false; - return render(newState) - .then(function() { - if (!conversationId && (viewState.type != CONVERSATION_TYPES.PUBLIC)) { - // If it's a new private conversation then we need to use the old - // web service function to create the conversation. - var otherUserId = getOtherUserId(); - return Repository.sendMessageToUser(otherUserId, text) - .then(function(message) { - newConversationId = parseInt(message.conversationid, 10); - newCanDeleteMessagesForAllUsers = message.candeletemessagesforallusers; - return message; - }); - } else { - return Repository.sendMessageToConversation(conversationId, text); - } - }) - .then(function(message) { + + render(newState); + + var sendMessagePromise = null; + var newCanDeleteMessagesForAllUsers = null; + if (!conversationId && (viewState.type != CONVERSATION_TYPES.PUBLIC)) { + // If it's a new private conversation then we need to use the old + // web service function to create the conversation. + var otherUserId = getOtherUserId(); + sendMessagePromise = Repository.sendMessageToUser(otherUserId, text) + .then(function(message) { + newConversationId = parseInt(message.conversationid, 10); + newCanDeleteMessagesForAllUsers = message.candeletemessagesforallusers; + return message; + }); + } else { + sendMessagePromise = Repository.sendMessageToConversation(conversationId, text); + } + + sendMessagePromise.then(function(message) { var newState = StateManager.addMessages(viewState, [message]); newState = StateManager.setSendingMessage(newState, false); var conversation = formatConversationForEvent(newState); @@ -1076,12 +1052,10 @@ function( newState = StateManager.setCanDeleteMessagesForAllUsers(newState, newCanDeleteMessagesForAllUsers); } - return render(newState) - .then(function() { - isSendingMessage = false; - PubSub.publish(MessageDrawerEvents.CONVERSATION_NEW_LAST_MESSAGE, conversation); - return; - }); + render(newState); + isSendingMessage = false; + PubSub.publish(MessageDrawerEvents.CONVERSATION_NEW_LAST_MESSAGE, conversation); + return; }) .catch(function(error) { isSendingMessage = false; @@ -1095,7 +1069,6 @@ function( * Toggle the selected messages update the statemanager and render the result. * * @param {Number} messageId The id of the message to be toggled - * @return {Promise} Renderer promise. */ var toggleSelectMessage = function(messageId) { var newState = viewState; @@ -1106,7 +1079,7 @@ function( newState = StateManager.addSelectedMessagesById(viewState, [messageId]); } - return render(newState); + render(newState); }; /** @@ -1115,10 +1088,45 @@ function( * @return {Promise} Renderer promise. */ var cancelEditMode = function() { - return cancelRequest(getOtherUserId()) + cancelRequest(getOtherUserId()); + var newState = StateManager.removeSelectedMessagesById(viewState, viewState.selectedMessageIds); + render(newState); + }; + + /** + * Process the patches in the render buffer one at a time in order until the + * buffer is empty. + * + * @param {Object} header The conversation header container element. + * @param {Object} body The conversation body container element. + * @param {Object} footer The conversation footer container element. + */ + var processRenderBuffer = function(header, body, footer) { + if (isRendering) { + return; + } + + if (!renderBuffer.length) { + return; + } + + isRendering = true; + var renderable = renderBuffer.shift(); + var renderPromises = renderers.map(function(renderFunc) { + return renderFunc(renderable.patch); + }); + + $.when.apply(null, renderPromises) .then(function() { - var newState = StateManager.removeSelectedMessagesById(viewState, viewState.selectedMessageIds); - return render(newState); + isRendering = false; + renderable.deferred.resolve(true); + // Keep processing the buffer until it's empty. + processRenderBuffer(header, body, footer); + }) + .catch(function(error) { + isRendering = false; + renderable.deferred.reject(error); + Notification.exception(error); }); }; @@ -1148,25 +1156,39 @@ function( return function(newState) { var patch = Patcher.buildPatch(viewState, newState); + var deferred = $.Deferred(); + + // Check if the patch has any data. Ignore empty patches. + if (Object.keys(patch).length) { + // Add the patch to the render buffer which gets processed in order. + renderBuffer.push({ + patch: patch, + deferred: deferred + }); + } else { + deferred.resolve(true); + } // This is a great place to add in some console logging if you need // to debug something. You can log the current state, the next state, // and the generated patch and see exactly what will be updated. - var renderPromises = renderers.map(function(renderFunc) { - return renderFunc(patch); - }); - return $.when.apply(null, renderPromises) - .then(function() { - viewState = newState; - if (newState.id) { - // Only cache created conversations. - stateCache[newState.id] = { - state: newState, - messagesOffset: getMessagesOffset(), - loadedAllMessages: hasLoadedAllMessages() - }; - } - return; - }); + + // Optimistically update the state. We're going to assume that the rendering + // will always succeed. The rendering is asynchronous (annoyingly) so it's buffered + // but it'll reach eventual consistency with the current state. + viewState = newState; + if (newState.id) { + // Only cache created conversations. + stateCache[newState.id] = { + state: newState, + messagesOffset: getMessagesOffset(), + loadedAllMessages: hasLoadedAllMessages() + }; + } + + // Start processing the buffer. + processRenderBuffer(header, body, footer); + + return deferred.promise(); }; }; @@ -1179,12 +1201,9 @@ function( var generateConfirmActionHandler = function(actionCallback) { return function(e, data) { if (!viewState.loadingConfirmAction) { - actionCallback(getOtherUserId()) - .catch(function(error) { - var newState = StateManager.setLoadingConfirmAction(viewState, false); - render(newState); - Notification.exception(error); - }); + actionCallback(getOtherUserId()); + var newState = StateManager.setLoadingConfirmAction(viewState, false); + render(newState); } data.originalEvent.preventDefault(); }; @@ -1232,7 +1251,7 @@ function( var element = target.closest(SELECTORS.MESSAGE); var messageId = parseInt(element.attr('data-message-id'), 10); - toggleSelectMessage(messageId).catch(Notification.exception); + toggleSelectMessage(messageId); data.originalEvent.preventDefault(); }; @@ -1244,7 +1263,7 @@ function( * @param {Object} data Data for this event. */ var handleCancelEditMode = function(e, data) { - cancelEditMode().catch(Notification.exception); + cancelEditMode(); data.originalEvent.preventDefault(); }; @@ -1413,10 +1432,9 @@ function( if (!isResetting && !isLoadingMoreMessages && !hasLoadedAllMessages() && hasMembers) { isLoadingMoreMessages = true; var newState = StateManager.setLoadingMessages(viewState, true); - render(newState) - .then(function() { - return loadMessages(viewState.id, LOAD_MESSAGE_LIMIT, getMessagesOffset(), NEWEST_FIRST, []); - }) + render(newState); + + loadMessages(viewState.id, LOAD_MESSAGE_LIMIT, getMessagesOffset(), NEWEST_FIRST, []) .then(function() { isLoadingMoreMessages = false; setMessagesOffset(getMessagesOffset() + LOAD_MESSAGE_LIMIT); @@ -1495,9 +1513,15 @@ function( * @param {Object} body Conversation body container element. * @param {Number|null} conversationId The conversation id. * @param {Object} loggedInUserProfile The logged in user's profile. - * @return {Promise} Renderer promise. */ var resetState = function(body, conversationId, loggedInUserProfile) { + // Reset all of the states back to the beginning if we're loading a new + // conversation. + isResetting = true; + isRendering = false; + renderBuffer = []; + isSendingMessage = false; + var loggedInUserId = loggedInUserProfile.id; var midnight = parseInt(body.attr('data-midnight'), 10); var initialState = StateManager.buildInitialState(midnight, loggedInUserId, conversationId); @@ -1510,7 +1534,7 @@ function( newMessagesPollTimer.stop(); } - return render(initialState); + render(initialState); }; /** @@ -1524,32 +1548,34 @@ function( var resetNoConversation = function(body, loggedInUserProfile, otherUserId) { // Always reset the state back to the initial state so that the // state manager and patcher can work correctly. - return resetState(body, null, loggedInUserProfile) - .then(function() { - if (loggedInUserProfile.id != otherUserId) { - // Private conversation between two different users. - return Repository.getConversationBetweenUsers( - loggedInUserProfile.id, - otherUserId, - true, - true, - 0, - 0, - LOAD_MESSAGE_LIMIT, - 0, - NEWEST_FIRST - ); - } else { - // Self conversation. - return Repository.getSelfConversation( - loggedInUserProfile.id, - LOAD_MESSAGE_LIMIT, - 0, - NEWEST_FIRST - ); - } - }) - .then(function(conversation) { + resetState(body, null, loggedInUserProfile); + + var resetNoConversationPromise = null; + + if (loggedInUserProfile.id != otherUserId) { + // Private conversation between two different users. + resetNoConversationPromise = Repository.getConversationBetweenUsers( + loggedInUserProfile.id, + otherUserId, + true, + true, + 0, + 0, + LOAD_MESSAGE_LIMIT, + 0, + NEWEST_FIRST + ); + } else { + // Self conversation. + resetNoConversationPromise = Repository.getSelfConversation( + loggedInUserProfile.id, + LOAD_MESSAGE_LIMIT, + 0, + NEWEST_FIRST + ); + } + + return resetNoConversationPromise.then(function(conversation) { // Looks like we have a conversation after all! Let's use that. return resetByConversation(body, conversation, loggedInUserProfile); }) @@ -1575,31 +1601,32 @@ function( // Always reset the state back to the initial state so that the // state manager and patcher can work correctly. - return resetState(body, conversationId, loggedInUserProfile) - .then(function() { - if (cache) { - // We've seen this conversation before so there is no need to - // send any network requests. - var newState = cache.state; - // Reset some loading states just in case they were left weirdly. - newState = StateManager.setLoadingMessages(newState, false); - newState = StateManager.setLoadingMembers(newState, false); - setMessagesOffset(cache.messagesOffset); - setLoadedAllMessages(cache.loadedAllMessages); - return render(newState); - } else { - return loadNewConversation( - conversationId, - loggedInUserProfile, - LOAD_MESSAGE_LIMIT, - 0, - NEWEST_FIRST - ); - } - }) - .then(function() { - return resetMessagePollTimer(conversationId); - }); + resetState(body, conversationId, loggedInUserProfile); + + var promise = $.Deferred().resolve({}).promise(); + if (cache) { + // We've seen this conversation before so there is no need to + // send any network requests. + var newState = cache.state; + // Reset some loading states just in case they were left weirdly. + newState = StateManager.setLoadingMessages(newState, false); + newState = StateManager.setLoadingMembers(newState, false); + setMessagesOffset(cache.messagesOffset); + setLoadedAllMessages(cache.loadedAllMessages); + render(newState); + } else { + promise = loadNewConversation( + conversationId, + loggedInUserProfile, + LOAD_MESSAGE_LIMIT, + 0, + NEWEST_FIRST + ); + } + + return promise.then(function() { + return resetMessagePollTimer(conversationId); + }); }; /** @@ -1618,30 +1645,31 @@ function( // Always reset the state back to the initial state so that the // state manager and patcher can work correctly. - return resetState(body, conversation.id, loggedInUserProfile) - .then(function() { - if (cache) { - // We've seen this conversation before so there is no need to - // send any network requests. - var newState = cache.state; - // Reset some loading states just in case they were left weirdly. - newState = StateManager.setLoadingMessages(newState, false); - newState = StateManager.setLoadingMembers(newState, false); - setMessagesOffset(cache.messagesOffset); - setLoadedAllMessages(cache.loadedAllMessages); - return render(newState); - } else { - return loadExistingConversation( - conversation, - loggedInUserProfile, - LOAD_MESSAGE_LIMIT, - NEWEST_FIRST - ); - } - }) - .then(function() { - return resetMessagePollTimer(conversation.id); - }); + resetState(body, conversation.id, loggedInUserProfile); + + var promise = $.Deferred().resolve({}).promise(); + if (cache) { + // We've seen this conversation before so there is no need to + // send any network requests. + var newState = cache.state; + // Reset some loading states just in case they were left weirdly. + newState = StateManager.setLoadingMessages(newState, false); + newState = StateManager.setLoadingMembers(newState, false); + setMessagesOffset(cache.messagesOffset); + setLoadedAllMessages(cache.loadedAllMessages); + render(newState); + } else { + promise = loadExistingConversation( + conversation, + loggedInUserProfile, + LOAD_MESSAGE_LIMIT, + NEWEST_FIRST + ); + } + + return promise.then(function() { + return resetMessagePollTimer(conversation.id); + }); }; /** @@ -1702,9 +1730,6 @@ function( } if (isNewConversation) { - // Reset all of the states back to the beginning if we're loading a new - // conversation. - isResetting = true; var renderPromise = null; var loggedInUserProfile = getLoggedInUserProfile(body); if (conversation) {