Create the Avatar feature module

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

In this section we create the Avatar feature module as shown in figure 6.7.

The chat object already provides for managing avatar information. We just need to decide on some details. Let’s revisit the Avatar UI as shown in figure 6.8.

Each online person has an avatar that’s shaped like a box with a thick border and with their name displayed in the center. The avatar that represents the user should have a blue border. The avatar for the chatee should have a green border. When we

Figure 6.7 The Avatar feature module in our SPA architecture

Figure 6.8 Avatars as we’d like them presented

215 Create the Avatar feature module

tap or click on an avatar, it should change color. After a long press or touch on an ava- tar, its appearance should change and we should be able to drag it to a new location.

We will develop our Avatar module using the typical process for feature modules:

■ Create a JavaScript file for the feature module using an isolated namespace.

■ Create the stylesheet file for the feature module with classes prefixed by the namespace.

■ Update the browser document to include the new JavaScript and stylesheet files.

■ Adjust the Shell to configure and initialize the new module.

We’ll follow these steps in the following sections.

6.5.1 Create the Avatar JavaScript

Our first step in adding the Avatar feature module is to create the JavaScript file. Since the module uses many of the same events as the Chat module, we can copy spa/js/

spa.chat.js to spa/js/spa.avtr.js and then adjust accordingly. Listing 6.15 is our freshly minted feature module file. Because this is so similar to Chat, we don’t offer an in- depth discussion. But the interesting parts have been annotated:

/*

* spa.avtr.js

* Avatar feature module

*/

/*jslint browser : true, continue : true, devel : true, indent : 2, maxerr : 50, newcap : true, nomen : true, plusplus : true, regexp : true, sloppy : true, vars : false, white : true

*/

/*global $, spa */

spa.avtr = (function () { 'use strict';

//--- BEGIN MODULE SCOPE VARIABLES --- var

configMap = {

chat_model : null, people_model : null, settable_map : {

chat_model : true, people_model : true }

},

stateMap = {

drag_map : null,

$drag_target : null,

Listing 6.15 Create the Avatar JavaScript—spa/js/spa.avtr.js

Employ the use strict pragma.

Declare configuration properties for the people and chat objects.

Declare state properties to allow us to track a dragged avatar between event handlers.

drag_bg_color: undefined },

jqueryMap = {}, getRandRgb, setJqueryMap, updateAvatar,

onTapNav, onHeldstartNav, onHeldmoveNav, onHeldendNav, onSetchatee, onListchange, onLogout,

configModule, initModule;

//--- END MODULE SCOPE VARIABLES --- //--- BEGIN UTILITY METHODS --- getRandRgb = function (){

var i, rgb_list = [];

for ( i = 0; i < 3; i++ ){

rgb_list.push( Math.floor( Math.random() * 128 ) + 128 );

}

return 'rgb(' + rgb_list.join(',') + ')';

};

//--- END UTILITY METHODS --- //--- BEGIN DOM METHODS --- setJqueryMap = function ( $container ) {

jqueryMap = { $container : $container };

};

updateAvatar = function ( $target ){

var css_map, person_id;

css_map = {

top : parseInt( $target.css( 'top' ), 10 ), left : parseInt( $target.css( 'left' ), 10 ), 'background-color' : $target.css('background-color') };

person_id = $target.attr( 'data-id' );

configMap.chat_model.update_avatar({

person_id : person_id, css_map : css_map });

};

//--- END DOM METHODS --- //--- BEGIN EVENT HANDLERS --- onTapNav = function ( event ){

var css_map,

$target = $( event.elem_target ).closest('.spa-avtr-box');

if ( $target.length === 0 ){ return false; }

$target.css({ 'background-color' : getRandRgb() });

updateAvatar( $target );

};

onHeldstartNav = function ( event ){

var offset_target_map, offset_nav_map,

$target = $( event.elem_target ).closest('.spa-avtr-box');

Create a utility to generate a random RGB color string.

Create the updateAvatar method to read the css values from the provided $target avatar, and then invoke the

model.chat.update_avatar method.

Create the onTapNav event handler, which is triggered when a user clicks or taps on the navigation area. This handler uses event delegation, as it only reacts if the element beneath the tap target is an avatar.

Otherwise, it ignores the event.

Create the

OnHeldstartNav event handler. This is triggered when the user starts a dragging motion in the navigation area.

217 Create the Avatar feature module

if ( $target.length === 0 ){ return false; } stateMap.$drag_target = $target;

offset_target_map = $target.offset();

offset_nav_map = jqueryMap.$container.offset();

offset_target_map.top -= offset_nav_map.top;

offset_target_map.left -= offset_nav_map.left;

stateMap.drag_map = offset_target_map;

stateMap.drag_bg_color = $target.css('background-color');

$target

.addClass('spa-x-is-drag') .css('background-color','');

};

onHeldmoveNav = function ( event ){

var drag_map = stateMap.drag_map;

if ( ! drag_map ){ return false; } drag_map.top += event.px_delta_y;

drag_map.left += event.px_delta_x;

stateMap.$drag_target.css({

top : drag_map.top, left : drag_map.left });

};

onHeldendNav = function ( event ) {

var $drag_target = stateMap.$drag_target;

if ( ! $drag_target ){ return false; }

$drag_target

.removeClass('spa-x-is-drag')

.css('background-color',stateMap.drag_bg_color);

stateMap.drag_bg_color= undefined;

stateMap.$drag_target = null;

stateMap.drag_map = null;

updateAvatar( $drag_target );

};

onSetchatee = function ( event, arg_map ) { var

$nav = $(this),

new_chatee = arg_map.new_chatee, old_chatee = arg_map.old_chatee;

// Use this to highlight avatar of user in nav area // See new_chatee.name, old_chatee.name, etc.

// remove highlight from old_chatee avatar here if ( old_chatee ){

$nav

.find( '.spa-avtr-box[data-id=' + old_chatee.cid + ']' ) .removeClass( 'spa-x-is-chatee' );

}

// add highlight to new_chatee avatar here if ( new_chatee ){

Create the onHeldmoveNav event handler, which is triggered when the user is in the process of dragging an avatar. This is executed frequently, so calculations are kept to a minimum.

Create the onHeldendNav event handler. This is triggered when the user releases an avatar after a drag. The handler returns the dragged avatar back to its original color. It then invokes the updateAvatar method to read the avatar details and invoke the model.chat.update_avatar ( <update_map> ) method.

Create the onSetchatee event handler. This is invoked when the Model publishes an spa-setchatee event.

In this module, we set the outline of the chatee avatar to green.

$nav

.find( '.spa-avtr-box[data-id=' + new_chatee.cid + ']' ) .addClass('spa-x-is-chatee');

} };

onListchange = function ( event ){

var

$nav = $(this),

people_db = configMap.people_model.get_db(), user = configMap.people_model.get_user(), chatee = configMap.chat_model.get_chatee() || {},

$box;

$nav.empty();

// if the user is logged out, do not render if ( user.get_is_anon() ){ return false;}

people_db().each( function ( person, idx ){

var class_list;

if ( person.get_is_anon() ){ return true; } class_list = [ 'spa-avtr-box' ];

if ( person.id === chatee.id ){

class_list.push( 'spa-x-is-chatee' );

}

if ( person.get_is_user() ){

class_list.push( 'spa-x-is-user');

}

$box = $('<div/>')

.addClass( class_list.join(' ')) .css( person.css_map )

.attr( 'data-id', String( person.id ) )

.prop( 'title', spa.util_b.encodeHtml( person.name )) .text( person.name )

.appendTo( $nav );

});

};

onLogout = function (){

jqueryMap.$container.empty();

};

//--- END EVENT HANDLERS --- //--- BEGIN PUBLIC METHODS --- // Begin public method /configModule/

// Example : spa.avtr.configModule({...});

// Purpose : Configure the module prior to initialization, // values we do not expect to change during a user session.

// Action :

// The internal configuration data structure (configMap) // is updated with provided arguments. No other actions // are taken.

// Returns : none

// Throws : JavaScript error object and stack trace on // unacceptable or missing arguments

//

Create the onListchange event handler.

This is invoked when the Model publishes an spa-listchange event. In this module, we redraw the avatars.

Create the onLogout event handler. This is invoked when the Model publishes an spa-logout event.

In this module, we remove all avatars.

219 Create the Avatar feature module

configModule = function ( input_map ) { spa.util.setConfigMap({

input_map : input_map,

settable_map : configMap.settable_map, config_map : configMap

});

return true;

};

// End public method /configModule/

// Begin public method /initModule/

// Example : spa.avtr.initModule( $container );

// Purpose : Directs the module to begin offering its feature // Arguments : $container - container to use

// Action : Provides avatar interface for chat users // Returns : none

// Throws : none //

initModule = function ( $container ) { setJqueryMap( $container );

// bind model global events

$.gevent.subscribe( $container, 'spa-setchatee', onSetchatee );

$.gevent.subscribe( $container, 'spa-listchange', onListchange );

$.gevent.subscribe( $container, 'spa-logout', onLogout );

// bind actions

$container

.bind( 'utap', onTapNav ) .bind( 'uheldstart', onHeldstartNav ) .bind( 'uheldmove', onHeldmoveNav ) .bind( 'uheldend', onHeldendNav );

return true;

};

// End public method /initModule/

// return public methods return {

configModule : configModule, initModule : initModule };

//--- END PUBLIC METHODS --- }());

Now that we have the JavaScript portion of the module complete, we can create the associated stylesheet.

6.5.2 Create the Avatar stylesheet

Our Avatar module draws boxes to graphically represent a user. We can define a sin- gle class (spa-avtr-box) to style the box. This class can then be modified to high- light the user (spa-x-is-user), highlight the chatee (spa-x-is-chatee), or highlight a box that’s being dragged (spa-x-is-drag). These selectors are shown in listing 6.16:

Create the code to bind Model-published events first.

Create the code to bind browser events next. Doing this before the Model events could result in a race condition.

/*

* spa.avtr.css

* Avatar feature styles

*/

.spa-avtr-box {

position : absolute;

width : 62px;

padding : 0 4px;

height : 40px;

line-height : 32px;

border : 4px solid #aaa;

cursor : pointer;

text-align : left;

overflow : hidden;

text-overflow : ellipsis;

border-radius : 4px;

text-align : center;

}

.spa-avtr-box.spa-x-is-user { border-color : #44f;

}

.spa-avtr-box.spa-x-is-chatee { border-color : #080;

}

.spa-avtr-box.spa-x-is-drag {

cursor : move;

color : #fff;

background-color : #000;

border-color : #800;

}

With the module files complete, we now need to adjust two additional files: the Shell and the browser document.

6.5.3 Update the Shell and the browser document

If we want to use the newly created feature module, we need to update the Shell to configure and initialize it, as shown in listing 6.17:

...

initModule = function ( $container ) { ...

// configure and initialize feature modules spa.chat.configModule({

set_chat_anchor : setChatAnchor, chat_model : spa.model.chat, people_model : spa.model.people

Listing 6.16 Create the Avatar stylesheet—spa/css/spa.avtr.css

Listing 6.17 Update the Shell to configure and initialize Avatar—spa/js/spa.shell.js Create the class used

to style the avatars.

Add a text-overflow:

ellipsis rule to elegantly truncate long text. We have to set the overflow:hidden rule as well or this won’t work.

Create a derived selector to style the avatar that represents the user.

Create a derived selector to style the avatar that represents the chatee.

Create a derived selector to style an avatar that is being moved by the user.

221 Create the Avatar feature module

});

spa.chat.initModule( jqueryMap.$container );

spa.avtr.configModule({

chat_model : spa.model.chat, people_model : spa.model.people });

spa.avtr.initModule( jqueryMap.$nav );

// Handle URI anchor change events.

...

};

...

The last step when creating a feature module is to update the browser document to include the JavaScript and stylesheet files. This step was already accomplished in chap- ter 5, but for the sake of completeness, the changes are shown again in listing 6.18:

...

<!-- our stylesheets -->

<link rel="stylesheet" href="css/spa.css" type="text/css"/>

<link rel="stylesheet" href="css/spa.shell.css" type="text/css"/>

<link rel="stylesheet" href="css/spa.chat.css" type="text/css"/>

<link rel="stylesheet" href="css/spa.avtr.css" type="text/css"/>

...

<!-- our javascript -->

...

<script src="js/spa.shell.js" ></script>

<script src="js/spa.chat.js" ></script>

<script src="js/spa.avtr.js" ></script>

...

The creation and integration of the Avatar feature module is complete. Now let’s test it out.

6.5.4 Test the Avatar feature module

When we load our browser document (spa/spa.html), we should see a page with

“Please sign in” in the user area on the upper-right. When we click on this, we can sign in as before. Once the chat slider opens, we should see an interface that looks like fig- ure 6.9.

We can now drag the avatars around (they all start in the top-left corner) by hold- dragging them. A tap on an avatar will result in a color change. After a little tapping and dragging, we should see the interface look something like figure 6.10. The user avatar has a blue border, the chatee has a green border, and any avatar that is being dragged has a black-white-red color scheme:

We’ve implemented all the features we discussed at the beginning of this chapter.

Now let’s look at how we accomplished one facet of our work that is a popular topic these days—data binding.

Listing 6.18 Update the browser document for avatars—spa/spa.html

First configure the feature module . . .

. . . then initialize it.

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

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

(433 trang)