Implementing the social view

While our app has three views, the start view is so similar to the previous project's start view that we won't go into great detail in this project about how it works. You're welcome to take a look at the code in the www/views/startView.html file.

The bulk of our code is going to reside in the social view and the tweet view, so that's where our primary focus will be. So let's get started!

Getting ready

Go ahead and create the socialView.html file now based on what we have discussed. Then we'll go over the portions you haven't seen before.

Getting on with it

When we're finished with this task, we should have a view that looks like this for iOS:

Getting on with it

The view for Android will be as follows:

Getting on with it

As with all our views to this point, we're going to start with the HTML portion that describes the actual view; it is given as follows:

<div class="viewBackground">
 <div class="navigationBar">
  <div id="socialView_title"></div>
  <button class="barButton backButton"   
      id="socialView_backButton" style="left:10px" ></button>
 </div>
 <div class="content avoidNavigationBar avoidToolBar" 
     style="padding:0; overflow: scroll;" 
     id="socialView_scroller">
   <div id="socialView_contentArea" style="padding: 0; 
     height: auto; position: relative;">
   </div>
 </div>
 <div class="toolBar" id="socialView_toolbar" style="text-
      align: center">
 </div>
</div>

Generally, this looks very much like our previous views, except that there are a couple of critical details. We've added a style to the inner div element. This takes away our default div styling (from www/framework/base.css) and forces the height to fit to the content (instead of to the screen). This means that when we want to scroll, we'll have the whole content to scroll through.

This is the first time we've talked about scrolling in our apps at all, actually, and for good reason: it's often hard on mobile platforms. In a perfect world, we could just rely on overflow:scroll to work on all our platforms, but that simply doesn't work. We can rely on native scrolling in iOS 5 and later, but that has its own share of problems (depending on the version of PhoneGap and various other WebKit gotchas), and rules out any lower platform, and of course, it doesn't work on Android at any version. So for iOS and Android, we'll have to use our own implementation for scrolling or use a third-party scrolling library such as iScroll 4. In this case, we're using our own implementation, which we'll cover a little later.

First we need to determine how our toolbar will show its profile images using the following template:

<div class="hidden" id="socialView_profileImageIcon">
 <a class="profileImage" style="background-
     image:url(%PROFILE_IMAGE_URL%)"
   href="javascript:socialView.loadStreamFor
     ('@%SCREEN_NAME%'),"></a>
</div>

Note that we have a little bit of JavaScript that fires when the user touches the image, this is to load the appropriate stream for that image.

Next, we need to define what the tweets should look like within our view. This is done by using the following code snippet:

<div class="hidden" id="socialView_twitterTemplate">
 <div class="twitterItem" onclick="socialView.selectTweet(%INDEX%);">
  <img src="%PROFILE_IMAGE_URL%" width=32 height=32 border=0  
   />
  <div class="twitterName">
   <span class="twitterRealName">%REAL_NAME%</span>
   <span class="twitterScreenName">@%SCREEN_NAME%</span>
  </div>
  <div class="twitterTweet">%TWEET%</div>
 </div>
</div>

In this segment of HTML, we've defined what the rest of a tweet should look like. We've given every div and span a class so that we can target them in our style.css file (located in www/style). That is mainly to keep the display of the tweet as separate from the content of the tweet as possible and to make it easy to change the look of a tweet whenever we want. Go ahead and take a look at the style.css file to get a good idea of how they will work to give our tweets some style.

Next up is our code:

  var socialView = $ge("socialView") || {};
  socialView.firstTime = true;
  socialView.currentStream = {}; 
  socialView.lastScrollTop = 0;
  socialView.myScroll = {};

As always, we give ourselves a namespace, in this case socialView. We also declare a few properties: firstTime, which will track if this is the first time our view is being displayed or not, and currentStream, which will hold the current visible stream from Twitter. The lastScrollTop property will record the position the user has scrolled to on our current page so we can restore it when they return from looking an individual tweet, and myScroll will hold our actual scroller.

  socialView.initializeView = function ()
  {
    PKUTIL.include ( ["./models/twitterStreams.js", 
        "./models/twitterStream.js"], function ()
                     {
                        // load our toolbar
                        TWITTER.loadTwitterUsers ( 
                        socialView.initializeToolbar );
                     }
                   );

    socialView.viewTitle = $ge("socialView_title");
    socialView.viewTitle.innerHTML = __T("APP_TITLE");

    socialView.backButton = $ge("socialView_backButton");
    socialView.backButton.innerHTML = __T("BACK");
    PKUI.CORE.addTouchListener(socialView.backButton, 
        "touchend", function () { PKUI.CORE.popView(); });

    if (device.platform != "WinCE")
    {
        socialView.myScroll = new SCROLLER. 
            GenericScroller ('socialView_contentArea'),
    }    
    
  }

Our initializeView() method isn't terribly different from our previous project. I've highlighted a couple lines, however – note that we load our models and when they are complete, we call TWITTER.loadTwitterUsers(). We pass along a completion function, which we define next so that when Twitter has returned the user data for all five of our Twitter users, we can call it.

We've also defined our scroller. If you want to see the complete code take a look in www/framework/scroller.js, but it should suffice to say, it is a reasonably nice scroller that is simple to use. It doesn't beat native scrolling, but nothing will. You're free to replace it with any library you'd like, but for the purposes of this project, we've gone this route.

  socialView.initializeToolbar = function ()
  {
    
    var toolbarHtml = "";
    var profileImageTemplate = 
        $ge("socialView_profileImageIcon").innerHTML;
    var users = TWITTER.users;
    
    if (users.error)
    {
        console.log (streams.error);
        alert ("Rate limited. Please try again later.");
    }

One of the first things we do after obtaining the template's HTML is to check on our TWITTER.users array. This array should have been filled with all sorts of user data, but if Twitter has rate-limited us for some reason, it may not be. So we check to see if there is an error condition, and if so, we let the user know. Granted, it's not the best method to let a user know, but for our example app, it suffices.

    // go through each stream and request the profile image
    for (var i=0; i<users.length; i++)
    {
        var theTemplate = profileImageTemplate.replace 
           ("%SCREEN_NAME%", users[i].getScreenName())
                          .replace ("%PROFILE_IMAGE_URL%", 
                             users[i].getProfileImageURL());
        toolbarHtml += theTemplate;
    }

Next, we iterate through each of the users. There should be five, but you could configure it for a different number and build up an HTML string that we'll put into the toolbar as follows:

    $ge("socialView_toolbar").innerHTML = toolbarHtml;
  }

Our next function, loadStreamFor() does the really hard work in this view. It requests a stream from Twitter and then processes it for display. The code snippet for it is as follows:

  socialView.loadStreamFor = function ( searchPhrase )
  {
    var aStream = new TWITTER.TwitterStream ( searchPhrase, 
    function ( theStream )
      {

Something to note is that we are now inside the completion function, the function that will be called when the Twitter stream is obtained.

        var theTweetTemplate = 
           $ge("socialView_twitterTemplate").innerHTML;
        var theContentArea = $ge("socialView_contentArea");
        var theStreamHTML = "";
        if (theStream.error)
        {
            console.log (theStream.error);
            alert ("Rate limited. Please try again later.");
        }

Because Twitter may rate-limit us at any time, we check again for any error in the stream in the preceding code snippet.

        for (var i=0; i<theStream.length; i++)
        {
          var theTweet = theStream[i];
          var theTemplate = 
              theTweetTemplate.replace("%INDEX%", i)
                           .replace ("%PROFILE_IMAGE_URL%",  
                            theTweet.profile_image_url ||    
                            theTweet.user.profile_image_url)
                           .replace ("%REAL_NAME%", 
                            theTweet.from_user || 
                            theTweet.user.name)
                           .replace ("%SCREEN_NAME%", 
                            theTweet.from_user || 
                            theTweet.user.screen_name)
                           .replace ("%TWEET%", 
                            theTweet.text);
          theStreamHTML += theTemplate;
        }

Here we're iterating through each item in the stream and building up a large HTML string from the template we defined earlier.

One important part to notice is how we're obtaining the data of the tweet, using theTweet.from_user || theTweet.user.screen_name and such. This is to deal with how Twitter returns a slightly different data format when searching for a word or a hashtag versus the data format when returning a user's timeline. Should one be undefined, we'll load the other, and since we can only get one or the other, it's easier than building a lot of if statements to take care of it.

        theContentArea.innerHTML = theStreamHTML;
        socialView.currentStream = theStream;
        if (socialView.myScroll.scrollTo)
        {
            socialView.myScroll.scrollTo ( 0, 0 );
        }

Once our stream HTML is built, we assign it to the content area so that the user can see it. We also store the stream into the currentStream property so we can reference it later. When that's done, we scroll to the top of the page so that the user can see the most recent tweets.

}
      , 100
    );
  }

That last 100? Well, it's actually part of the call to TwitterStream(). It's the number of items to return in the stream.

Our next function deals with what should happen when a user taps on a displayed tweet:

  socialView.selectTweet = function ( theIndex )
  {
     var theTweet = socialView.currentStream[theIndex];
     tweetView.setTweet ( theTweet );
     PKUI.CORE.pushView ( tweetView );
  }

This function is pretty simple. All we do is tell the tweet view what tweet was tapped, and then push it on to the view stack.

  socialView.viewWillAppear = function ()
  {
    document.addEventListener("backbutton", 
        socialView.backButtonPressed, false );
    if (socialView.firstTime)
    {
        socialView.loadStreamFor ( "@photokandy" ); 
        socialView.firstTime = false;
    }
    if (socialView.myScroll.scrollTo)
    {
      PKUTIL.delay ( 50, function ()
        {
          socialView.myScroll.scrollTo ( 0, 
             socialView.lastScrollTop );
        }
      );
    }
  }

This viewWillAppear() method is pretty similar to the last project except for the middle and the last portion. In the middle we're checking if this is the first time the view has been displayed. If it is, we want to load a default stream for the user. Remember, up till now we've only loaded a stream when the user taps on a profile image in the toolbar. But we don't want to reload this stream every time our view displays; we could be coming back from the tweet view and the user might want to continue where they left off in the previous stream. In the final portion, we're checking to see if we had a previous scroll position, and if so, we scroll the view to that point. We have to create a delay here, since if we set it too early, the view will be offscreen (and won't scroll), or it will be onscreen, and it'll be noticeable to the user.

The remaining two functions, viewWillHide() and backButtonPressed() present no new functionality, so while you do need them in your code, we won't go over them here.

That's it, not terribly difficult, but it does what we need–display a list of tweets. Once a user taps on the tweet, they'll be taken to the tweet view to do more, and that's what we'll look at in the next task.

What did we do?

In this task we defined the HTML code and templates for our social view. We also used the Twitter-stream data to construct a Twitter stream that the end user can interact with.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.219.45.185