socialize:messaging

v0.4.4Published 8 years ago

This package has not had recent updates. Please investigate it's current state before committing to using it in your project.

Messaging

Provides social network style messaging between users.

Features

  • Multi User Conversations
  • Read Status - has the participating user viewed the conversation since the last message was sent.
  • Typing Status - Is the participating user typing.
  • Observing Status - Is the participating user viewing the conversation.
  • inFlight Status - Has the message reached the server and been saved to the database yet.

Conversations

A conversation is a group of users (participants) and the messages sent amongst them. To create a new conversation you construct a new instance of Conversation and then call it's save method. This will add the currently logged in user as a participant in the conversation. From there the currently logged in user can add further participants that they wish to have participate in the conversation.

1var conversation = new Conversation().save();
2
3conversation.addParticipant( Meteor.users.findOne({username:"JohnDoe"}) );
4
5conversation.sendMessage("Hello World!");

Conversation (class) - Extends BaseModel

To gain access to the methods of a conversation you must first have an instance of a conversation. To obtain an instance of conversation you need to query the conversations collection (Meteor.conversations). A findOne will return a sinle instance and a find will return a cursor that when iterated over will return conversation instances. Ways of obtaining instances that belong to the current user are provided as extensions to the User class and are detail in the User Extension section of this document

1var conversation = Meteor.conversations.findOne(); // Single Conversation Instance
2
3var conversations = Meteor.conversations.find(); // Cursor Returning Conversation Instances

Instance Methods

All examples assume an instance of conversation named conversation for JavaScript examples, and that the current context is a conversation for HTML (spacebars) examples.

participants(limit, skip, sortBy, sortOrder) - returns cursor of participants as instances of Participant.

1conversation.participants(/*optional params*/).forEach(function(participant){
2	console.log(participant.user().username);
3});
1{{#each participants}}
2	{{user.username}}
3{{/each}}

isUnread() - Check if the currentUser has not read the conversation.

1if(conversation.isUnread()){
2	console.log("Conversation has not been read by the logged in user");
3}
1<div class="conversation {{#if isUnread}}unread{{/if}}">
2	
3</div>

isReadOnly() - Check if the currentUser is the last user participating in the conversation and therefore the conversation can't have any messages added to it.

1if(conversation.isReadOnly()){
2	console.log("You can't respond to this conversation");
3}
1<textarea {{#if isReadOnly}}disabled{{/if}}>

messages(limit, skip, sortBy, sortOrder) - returns a cursor of message instances for the conversation.

1conversation.messages(/*optional params*/).forEach(function(message){
2	console.log(message.user().username, ": ", message.body);
3});
1{{#each messages}}
2	{{message.user.username}}: {{message.body}}
3{{/each}}

lastMessage() - Get the message the was most recently added to the conversation.

1console.log(conversation.lastMessage());
1{{lastMessage.user.username}}: {{lastMessage.body}}

sendMessage(body) - Add a message to the conversation from the current user.

1Template.conversation.events({
2	'submit #replyForm': function(event, template) {
3		var body = template.$("textarea").val();
4		this.sendMessage(body);
5	}
6});

addParticipants(participants) - Add participants to the conversation. 'participants` parameter takes an array of user instances.

1var users = Meteor.users.find().fetch();
2
3conversation.addParticipants(users)

addParticipant(participant) - Add a single participant to the conversation. participant parameter takes a single user instance.

1var user = Meteor.users.findOne({username:"copleykj"});
2
3conversation.addParticipant(user);

updateReadState(state) - Manually update the read state of the conversation for the currentUser.. This is generally handled automatically through subscribing to the viewingConversation publication. Subscribing to this subscription not only sets the conversation as read by the user but also notes the user as observing the conversation so that when a new message is added, the read state is only set to false for users not observing. Unsubscribing from this subscription sets observing to false and read will be set to true for the participant when new messages come in.

1conversation.updateReadState(false); //set the conversation to unread

readBy() - returns the string "read by" followed by a a serialized sentence of the users who have read the conversation.

1{{readBy}}
1console.log(conversation.readBy()); //=> read by copleykj

removeParticipant(participant) - Remove a user from the conversation. participant param defaults to the currently logged in user. From the client the currently logged in user can only remove themselves.

1Template.conversation.events({
2	'click #leaveConversation': function() {
3		this.removeParticipant(); //remove the current user from the conversation
4	}
5});

Participants

A participant links a user with a conversation and holds information about the user that pertains to the current conversation such as if the user has read the conversation since the last message was sent and if user is currently viewing the conversation.

Participants are created by calling the addParticipant or addParticipants method of a conversation and passing a user instance or an array of user instances for addParticipants

1var conversation = Meteor.conversations.findOne();
2
3var user = Meteor.users.findOne({username:"JohnDoe"});
4
5conversation.addParticipant(user);
6
7var users = Meteor.users.find().fetch();
8
9conversation.addParticipants(users);

Participant (class) - Extends BaseModel

To gain access to the methods of a participant you must first have an instance of the Participant class. To obtain in instance you will need to query the participants collection (Meteor.participants) or use methods provided by the Conversation class to retrieve participants relevant to that conversation.

Instance Methods

All examples assume in instance of Participant named participant for JavaScript examples and that the current context is an instance of Participant for HTML (spacebars) examples.

user() - returns the User instance that the participant record represents.

1console.log(participant.user().username);
1{{user.username}}

conversation() - The Conversation instance that the user is participating in.

1console.log(participant.conversation().lastMessage());
1{{conversation.lastMessage}}

isObserving() - Check if the user is currently observing this conversation.

1<!-- context is conversation -->
2{{#each participants}}
3	<div class="participant {{#if isObserving}}observing{{/if}}">
4
5	</div>
6{{/each}}

Messages

A message is a bit of text linked to a conversation and a user and timestamped. Creating a new message is accomplished by calling the sendMessage method of a conversation and providing a string as it's only parameter.

1var conversation = Meteor.conversations.findOne();
2
3conversation.sendMessage("Hello World!");

Message (class) - Extends BaseModel

Instance Methods

All examples assume an instance of Message named message for JavaScript examples and that the context is an instance of Message for HTML (spacebars) examples.

user - The user instance of the user who sent the message.

1console.log(message.user().username, " says, ", message.body);
1{{user.username}} says, {{message.body}}

timestamp - A string representation of when the message was sent.

1<span class="timeago" data-timestamp="{{timestamp}}"></span>

isInFlight - Whether or not the message has been received.

1{{#unless isInFlight}}
2	<i class="icon-check-mark></i>
3{{/unless}}

User Extensions

This package extends the socialize:user-model package with properties and methods that apply to the user in the context of messaging.

Instance Methods

conversations(limit, skip, sortBy, sortOrder) - Get the converations the user is participating in.

1{{#each currentUser.conversations}}
2	<div class="conversation">
3		{{#with lastMessage}}
4			{{user.username}}: {{body}}
5		{{/with}}
6	</div>
7{{/each}}

isParticipatingIn(conversation) - check if the user is participating in a conversation.

1if(!currentUser.isParticipatingIn(conversation)){
2	throw new Meteor.error("Not Authorized", "sorry you can't send a message to this conversation because you have not been added to it");
3}

findExistingConversationWithUsers(users, callback) - Find and return the _id of an existing conversation between a set of users. This makes a server call so a callback that takes the standard (error, result) parms is required

1    var participants = [user1._id, user2._id];
2
3    Meteor.user().findExistingConversationWithUsers(participants, function(error, result){
4        if(result){
5            Router.go("conversation", {_id:result});
6        }
7    })

Publications

Data

This package provides some publictions for convienience.

conversations {limit:Number, skip:Number} - Publishes conversations the user is involved in with the participants for each conversation and the last message that was sent to the conversation. (To get all message for a conversation subscribe to the "messagesFor" publication)

1Meteor.subscribe('conversations', {limit:10, skip:10});

messagesFor "conversationId" {limit:Number, skip:Number} - Publishes the messages for a particular conversation.

1Meteor.subscribe('messagesFor', "fMXAoZPxNQGCGCPZQ", {limit:10, skip:10});

Stateful

These publicatons set certain states for the participant in a conversation. I've chosen to maintain state this way because it maximizes reliability. If the state was set with method calls or collection updates the user could navigate away or the browser could close before the calls execute. With subscriptions they stop when the connection breaks and thus are useful for maintaining state that needs updated when the user leaves the site.

viewingConversation "conversationId" - This publication handles conversation state, setting the observing and read status for the participant. This publication should be subscribed to when the user is viewing the messages for a conversation and should be unsubscribed from when the user is no longer viewing them. Subscribing to this using iron:router's subscriptions option is best as it will handle subcribing when the route is navigated to and unsbscribing when the route is navigated away from.

1Meteor.subscribe('viewingConversation', "fMXAoZPxNQGCGCPZQ");

typing "conversationId" - This publication handles the typing state. This can be subscribed to on a keypress event and using a setTimeout which is cleared and reset on each key stroke, can be cleared when the time out is allowed to execute or the message is finally sent.

1Meteor.subscribe('typing', "fMXAoZPxNQGCGCPZQ");