Add Avatar support to the Model

Một phần của tài liệu single page web applications (Trang 221 - 226)

The Avatar capability is relatively easy to add because we can build on the messaging infrastructure of the chat object. The primary reason we present this capability is to show other uses for near-real-time messaging. The fact that it shows well at confer- ences is just icing on the cake. First we’ll update the Model.

6.3.1 Add Avatar support to the chat object

The changes we require for the chat object to support avatars are relatively modest.

We only need to add the update_avatar method, which will send an updateavatar message to the backend with a map describing which avatar changed and how. We expect the backend to send a listchange message when an avatar is updated, and the code to handle that message is already written and tested.

Let’s update the Model as shown in listing 6.8. Changes are shown in bold:

This method returns true on success.

Set the chatee to the person with ID id_03.

Send a “What is up, tricks?”

message to the chatee. This is the last person who sent to the user.

An spa-updatechat event is published, which invokes the function subscribed on $t for the event.

We see a response to our message and an spa-updatechat event is published and this invokes the function subscribed on $t for the event.

The spa-setchatee event is published.

The spa- updatechat message is published, which invokes the function subscribed on $t. Another automated

response is received.

Confirm the set_chatee method returns true on success.

Send a “Hi Pebbles!”

message to our current

chatee, Pebbles. This method returns true on success.

197 Add Avatar support to the Model

...

// If the user is anonymous or the chatee is null, it // aborts and returns false.

// * update_avatar( <update_avtr_map> ) - send the // update_avtr_map to the backend. This results in an // an 'spa-listchange' event which publishes the updated // people list and avatar information (the css_map in the // person objects). The update_avtr_map must

// have the form { person_id : person_id, css_map : css_map } //

// jQuery global custom events published by the object include:

...

chat = (function () { var

_publish_listchange, _publish_updatechat, _update_list, _leave_chat,

get_chatee, join_chat, send_msg, set_chatee, update_avatar, chatee = null;

...

// avatar_update_map should have the form:

// { person_id : <string>, css_map : { // top : <int>, left : <int>,

// 'background-color' : <string>

// }};

//

update_avatar = function ( avatar_update_map ) {

var sio = isFakeData ? spa.fake.mockSio : spa.data.getSio();

if ( sio ) {

sio.emit( 'updateavatar', avatar_update_map );

} };

return {

_leave : _leave_chat, get_chatee : get_chatee,

join : join_chat,

send_msg : send_msg, set_chatee : set_chatee, update_avatar : update_avatar };

}());

...

We’ve completed adding all the methods and events we designed for the chat object.

In the next section we’ll update the Fake module to emulate the server interaction to support avatars.

Listing 6.8 Update the Model to support avatars—spa/js/spa.model.js Add documentation

from our API specification.

Declare the update_avatar method variable.

Create the update_avatar method. We send an updateavatar message to the backend with a map as data.

Add update_avatar to the list of exported public methods.

6.3.2 Modify Fake to emulate avatars

Our next step is to modify the Fake module to support sending an updateavatar mes- sage to the backend whenever the user drops an avatar to a new location or clicks on the avatar to change its color. When Fake receives this message, it should:

■ Simulate sending an updateavatar message to the server.

■ Simulate receiving a listchange message from the server with an updated peo- ple list.

■ Execute the callback registered for the listchange message, providing it the updated people list.

These three steps can be accomplished as shown in listing 6.9. Changes are shown in bold:

...

emit_sio = function ( msg_type, data ) { var person_map, i;

...

if ( msg_type === 'leavechat' ) { // reset login status

delete callback_map.listchange;

delete callback_map.updatechat;

if ( listchange_idto ) {

clearTimeout( listchange_idto );

listchange_idto = undefined;

}

send_listchange();

}

// simulate send of 'updateavatar' message and data to server if ( msg_type === 'updateavatar' && callback_map.listchange ) { // simulate receipt of 'listchange' message

for ( i = 0; i < peopleList.length; i++ ) {

if ( peopleList[ i ]._id === data.person_id ) { peopleList[ i ].css_map = data.css_map;

break;

} }

// execute callback for the 'listchange' message callback_map.listchange([ peopleList ]);

} };

...

Now that we have the chat object and Fake updated, we can test avatars.

Listing 6.9 Modify Fake to support avatars—spa/js/spa.fake.js

Declare the i loop variable.

Create a handler for receipt of an updateavatar message.

Find the person object specified by the data from the updateavatar message and change its css_map property.

Execute the callback registered for the listchange message.

199 Add Avatar support to the Model

6.3.3 Test avatar support

This is our final bit of Model testing. Again, let’s load our browser document (spa/

spa.html) and ensure the SPA works as before. We’ll open the JavaScript console and test our update_avatar method as shown in listing 6.10. Typed input is shown in bold;

output is shown in italics:

// create a jQuery collection var $t = $('<div/>');

// bind functions to test global events

$.gevent.subscribe( $t, 'spa-login', function( event, user ) { console.log('Hello!', user.name); });

$.gevent.subscribe( $t, 'spa-listchange', function( event, changed_list ) {

console.log( '*Listchange:', changed_list );

});

// sign-in, wait 3s

spa.model.people.login( 'Jessy' );

>> Hello! Jessy

>> *Listchange: [Array[5]]

// get the Pebbles person

var person = spa.model.people.get_by_cid( 'id_03' );

// inspect avatar information JSON.stringify( person.css_map );

>> "{"top":100,"left":20,

>> "background-color":"rgb( 128, 192, 192)"}"

// update the avatar information spa.model.chat.update_avatar({

person_id : 'id_03', css_map : {} });

>> *Listchange: [Array[5]]

// get Pebbles again

person = spa.model.people.get_by_cid( 'id_03' );

// and now inspect

JSON.stringify( person.css_map );

>> {}

We’ve completed the chat object. As with the people object from chapter 5, the test- ing is reassuring, and we can add to a test suite for use without a server or browser.

6.3.4 Test-driven development

All those test-driven development (TDD) freaks out there are probably looking at all this manual testing and thinking “Gosh, why not just put this into a test suite that can

Listing 6.10 Test the update_avatar method

Create a jQuery collection ($t) that isn’t attached to the browser document. We’ll use this for event testing.

Have the $t jQuery collection subscribe to the spa-login event with a function that prints to the

console. Have the $t jQuery collection

subscribe to the spa- listchange event with a function that prints

“*Listchange:” and the changed_list. Sign in as

Jessy.

Three seconds later an spa- login event is published and this invokes the function subscribed on

$t for the event.

Get the person object for ID id_03, Pebbles.

Inspect the avatar information for the Pebbles person.

An spa-listchange event is also published, which invokes the associated function subscribed on $t for the event.

Use the update_avatar method to change the css_map for the Pebbles person object.

Confirm the update_avatar method publishes an spa-listchange event, which invokes the function subscribed on $t for the event.

The updated css_map for the Pebbles person object.

run automatically?” Being aspiring freaks ourselves, we can—and we did. Check out appendix B to see how one can use Node.js to automate this process.

We actually found a few issues as the result of the test suite. Most were specific to testing, so we will leave those to the appendix. But there were two bona fide bugs we needed to fix: our sign-out mechanism wasn’t quite right, as it wasn’t clearing the user list properly, and the chatee object wasn’t being updated properly after an spa.model.chat.update_avatar method call. Let’s fix both of those now as shown in listing 6.11. Changes are shown in bold:

...

people = (function () { ...

logout = function () { var user = stateMap.user;

chat._leave();

stateMap.user = stateMap.anon_user;

clearPeopleDb();

$.gevent.publish( 'spa-logout', [ user ] );

};

...

}());

chat = (function () { ...

// Begin internal methods

_update_list = function( arg_list ) {

var i, person_map, make_person_map, person, people_list = arg_list[ 0 ],

is_chatee_online = false;

clearPeopleDb();

PERSON:

for ( i = 0; i < people_list.length; i++ ) { person_map = people_list[ i ];

if ( ! person_map.name ) { continue PERSON; }

// if user defined, update css_map and skip remainder

if ( stateMap.user && stateMap.user.id === person_map._id ) { stateMap.user.css_map = person_map.css_map;

continue PERSON;

}

make_person_map = {

cid : person_map._id, css_map : person_map.css_map, id : person_map._id, name : person_map.name };

person = makePerson( make_person_map );

Listing 6.11 Fix sign-out and chatee object update—spa/js/spa.model.js

Remove the

is_removed variable.

Clear the people Taffy collection on logout.

Declare the person object.

Assign the results of makePerson to the person object.

201 Complete the Chat feature module

if ( chatee && chatee.id === make_person_map.id ) { is_chatee_online = true;

chatee = person;

} }

stateMap.people_db.sort( 'name' );

// If chatee is no longer online, we unset the chatee // which triggers the 'spa-setchatee' global event if ( chatee && ! is_chatee_online ) { set_chatee(''); } };

...

}());

...

This is a good point to take a break. In the remainder of the chapter we’ll return to the UI and finish the Chat feature module using the chat and people object APIs provided by the Model. We’ll also create an Avatar feature module.

Một phần của tài liệu single page web applications (Trang 221 - 226)

Tải bản đầy đủ (PDF)

(433 trang)