<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Activetuts+ &#187; Widgets</title>
	<atom:link href="http://active.tutsplus.com/category/tutorials/widgets/feed/" rel="self" type="application/rss+xml" />
	<link>http://active.tutsplus.com</link>
	<description>Flash, Flex &#38; ActionScript Tutorials</description>
	<lastBuildDate>Fri, 19 Mar 2010 19:32:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Build a Photo Viewer Using Flex and the Flickr API</title>
		<link>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 12:00:53 +0000</pubDate>
		<dc:creator>Matthew Casperson</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1918</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/092_Flickr/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial you will learn how to use the as3flickrlib library to create a Flash Flickr photo viewer.</p>
<p><span id="more-1918"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/092_Flickr/ImageFader.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/092_Flickr/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Step 1: The as3flickrlib</h2>
<p>There are many libraries available for Flex developers that interface with Flickr. The as3flickrlib library was created by Adobe and is the library that we&#8217;ll use to create this photo viewing application. You&#8217;ll need to download a copy of the as3flickrlib code for yourself, as well as the as3corelib library (as3flickrlib depends on as3corelib). Both can be obtained from <a href="http://labs.adobe.com/wiki/index.php/ActionScript_3:resources:apis:libraries">here</a>.</p>
<h2>Step 2: TweenMax</h2>
<p>You&#8217;ll also need the TweenMax library. TweenMax is a tweening library, which allows us to easily change the properties of an object over time. You can get TweenMax <a href="http://blog.greensock.com/tweenmaxas3/">here</a>.</p>
<h2>Step 3: New Project</h2>
<p>Create a new Flex web project and add the three libraries mentioned above to the Source Path of the application.</p>
<div class="tutorial_image"><img height="200" src="http://flashtuts.s3.cdn.plus.org/092_Flickr/step3.png" width="600" /></div>
<h2>Step 4: Wrapper Class</h2>
<p>This application works by taking the images loaded from Flickr and adding them to the main Application object (i.e. the object that is created by the MXML file). When you load an image off the web it is returned to you as a Bitmap. While the Bitmap class extends the DisplayObject class (which is what the addChild function requires), Flex will only allow those classes that extend the UIComponent class to be added as a child of the main Application object, and the Bitmap does not extend the UIComponent. The compiler will not flag adding a Bitmap to the Application object via the addChild function as an error, but you will get an exception at run time.</p>
<p>Still, it would be nice to be able to add the Bitmap objects as children of the Application object. We need to create a small wrapper class that does extend the UIComponent class (so it can be added to the Application), but also adds a Bitmap as a child of itself. That wrapper class is called DisplayObjectUIComponent.</p>
<pre name="code" class="javascript">
package
{
	import flash.display.DisplayObject;

	import mx.core.UIComponent;

	public class DisplayObjectUIComponent extends UIComponent
	{
		public function DisplayObjectUIComponent(displayObject:DisplayObject)
		{
		    super ();

		    explicitHeight = displayObject.height;
		    explicitWidth = displayObject.width;
		    addChild (displayObject);
		}
	}
}
</pre>
<h2>Step 5: New MXML File</h2>
<p>Now we need to create the MXML file. </p>
<pre name="code" class="javascript">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;mx:Application
  xmlns:mx=&quot;&lt;a href=&quot;http://www.adobe.com/2006/mxml&quot;&gt;http://www.adobe.com/2006/mxml&lt;/a&gt;&quot;
  layout=&quot;absolute&quot;
  backgroundGradientAlphas=&quot;[1.0, 1.0]&quot;
  backgroundGradientColors=&quot;[#000000, #5B5B5B]&quot;
  creationComplete=&quot;onComplete()&quot;&gt;

  ...

&lt;/mx:Application&gt;
</pre>
<p>This is the shell of the MXML file. Most of the code is the same as the empty template that is created when you open up a new Flex application in Flex Builder. In addition we&#8217;ve specified the background colors (with the <em>backgroundGradientAlphas</em> and <em>backgroundGradientColors</em> attributes) and set the onComplete function to be called when the Application object has created itself (with the <em>creationComplete</em> attribute).</p>
<h2>Step 6: mx:script Tag</h2>
<p>The code that will do the job of downloading and displaying the Flickr images needs to be contained in an mx:script tag. The &lt;![CDATA[ ... ]]&gt; tag just allows us to write code without having to worry about special characters like greater-than and less-than (&lt; and &gt;) being interpreted as part of the XML document.</p>
<pre name="code" class="javascript">
&lt;mx:Script&gt;
  &lt;![CDATA[

  ...

  ]]&gt;
&lt;/mx:Script&gt;
</pre>
<h2>Step 7: Import Classes</h2>
<p>We need to import some classes for use within our application.</p>
<pre name="code" class="javascript">
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import com.adobe.webapis.flickr.*;
import com.adobe.webapis.flickr.events.*;
import gs.TweenMax;
import gs.easing.*;
</pre>
<h2>Step 8: Define Constants</h2>
<p>Next we need to define some constants that will control how our application works.</p>
<pre name="code" class="javascript">
private static const SEARCH_STRING:String = "sunset";
private static const MAX_RESULTS:int = 50;
private static const API_KEY:String = "your key goes here";
private static const TRANSITION_TIME:Number = 1;
private static const DISPLAY_TIME:Number = 3;
</pre>
<ul>
<li>SEARCH_STRING defines the query that will be sent to Flickr. In essence we&#8217;ll be querying Flickr for images much like you would query Google for web pages. We have set the query to &quot;sunset&quot; here, but this string could be anything like &quot;kittens&quot;, &quot;mountains&quot;, &quot;cars&quot; etc.</li>
<li>MAX_RESULTS defines how many images Flickr will return once it has been queried.</li>
<li>API_KEY is your own Flickr API key, which you can apply for <a href="http://www.flickr.com/services/api/keys/apply/">here</a>.</li>
<li>TRANSITION_TIME defines how quickly the images will fade into each other in seconds. Here we&#8217;ve set the transition time to take 1 second.</li>
<li>DISPLAY_TIME defines how long each image will be displayed before the next image is loaded. Here we&#8217;ve set each image to be displayed for 3 seconds.</li>
</ul>
<h2>Step 9: Define Variables</h2>
<p>We need to define a few variables for our application.</p>
<pre name="code" class="javascript">
private var photos:ArrayCollection = null;
private var currentImage:int = 0;
private var displayImage:Bitmap = null;
private var backgroundImage:Bitmap = null;
</pre>
<ul>
<li>The photos variable is a collection of the photo definitions sent back by Flickr. It&#8217;s important to note that Flickr does not actually send back the photos themselves, but only the information needed to find the URL of the photo, which then has to be downloaded separately.</li>
<li>The currentImage variable maintains an index in the photos collection. This is so we know what photo needs to be displayed next.</li>
<li>The displayImage and backgroundImage variables are references to the Bitmap objects that are created by loading the Flickr images.</li>
</ul>
<h2>Step 10: Policy Files</h2>
<p>By default a Flash application can only load resources from it&#8217;s own domain. In order to load resources from another domain (like Flickr) the owner of that domain needs to have a policy file, usually called crossdomain.xml, that lets the Flash runtime know that it&#8217;s OK to load their resources. This policy file needs to be loaded before any attempts are made to load the resources.</p>
<p>Flickr hosts it&#8217;s images on a number of servers, so here we load the policy file of these servers. If you don&#8217;t perform this step you&#8217;ll get an exception when trying to load images off these domains.</p>
<pre name="code" class="javascript">
Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");
</pre>
<h2>Step 11: onComplete Function</h2>
<p>When the Flex application has finished creating itself, the onComplete function will be called (this is what we specified in Step 5). The onComplete<br />
function is the entry point of the application.</p>
<pre name="code" class="javascript">
private function onComplete():void
{
	var service:FlickrService = new FlickrService(API_KEY);
	service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);
	service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);
}
</pre>
<p>The first thing we need to do is create a new instance of the FlickrService class. The FlickrService object is our gateway to Flickr, and we use that to submit our search for our sunrise images. You need to supply the Flickr API key (from Step <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> to the FlickrService constructor.</p>
<pre name="code" class="javascript">var service:FlickrService = new FlickrService(API_KEY);</pre>
<p>Next we attach a function to the FlickrResultEvent.PHOTOS_SEARCH event. This function will be called when Flickr has returned some information about a search. Here we attach the onPhotosSearch function.</p>
<pre name="code" class="javascript">service.addEventListener(FlickrResultEvent.PHOTOS_SEARCH, onPhotosSearch);</pre>
<p>Finally we perform the actual search itself. The search function has a lot of parameters that can be used to narrow a search down to a specific user, date, title and more. We&#8217;re only interested in finding photos with the tag sunset, and so supply either a null, empty string or -1 to these other parameters.</p>
<pre name="code" class="javascript">service.photos.search("", SEARCH_STRING, "any", "", null, null, null, null, -1, "", MAX_RESULTS, 1);</pre>
<h2>Step 12: onPhotoSearch Function</h2>
<p>The onPhotoSearch function is called when Flickr has returned some information about our search.</p>
<pre name="code" class="javascript">private function onPhotosSearch(event:FlickrResultEvent):void
{
	if (event.success)
	{
		var photoList:PagedPhotoList = event.data.photos;
		photos = new ArrayCollection( photoList.photos );
		loadNextImage();
	}
	else
	{
		Alert.show(&quot;Flickr call failed. Did you update the API Key?&quot;);
	}
}</pre>
<p>We first need to determine if the call to Flickr was successful. This is done by checking the event.success flag. If this is true Flickr has successfully returned some information about the photos we queried it for. If event.success is false then the call failed. This usually happens because the API key that was supplied was incorrect.</p>
<pre name="code" class="javascript">
if (event.success)
{
	...
}
else
{
	...
}
</pre>
<p>If the call was successful we need to get access to the collection of photo data that was returned.</p>
<pre name="code" class="javascript">var photoList:PagedPhotoList = event.data.photos;</pre>
<p>The PagedPhotoList then contains the details of the photos themselves, which we then save in the photos collection.</p>
<pre name="code" class="javascript">photos = new ArrayCollection( photoList.photos );</pre>
<p>At this point the photos collection contains a list of photo details which can then be used to load the actual photo images. From here on in we&#8217;ll just be downloading images, from the URLs we created using the information in the photos collection, without any more special calls using the Flickr API.</p>
<p>To start the photo album, we need to call the loadNextImage function.</p>
<pre name="code" class="javascript">loadNextImage();</pre>
<p>If there was a problem calling Flickr the user is notified with an Alert window.</p>
<pre name="code" class="javascript">Alert.show(&quot;Flickr call failed. Did you update the API Key?&quot;);</pre>
<h2>Step 13: loadNextImage Function</h2>
<p>Now that we have the details of the photos that relate to our search, we need to actually download the images so they can be displayed. This is done by the loadNextImage function.</p>
<pre name="code" class="javascript">
private function loadNextImage():void
{
	var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';

	++currentImage;
	currentImage %= photos.length;

	var request:URLRequest = new URLRequest(imageURL);
	var loader:Loader = new Loader();
	loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);

	loader.load(request);
}</pre>
<p>Remember that I said that the call to Flickr does not actually return the images themselves? What it does return is the information needed to<br />
construct the URL that we can use to download the image. By using the server, id and secret information of the photos we can create the full URL that will display the image.</p>
<p>Each image has a number of resolutions. We pick which size image we are downloading by the suffix of the url. The _m suffix indicates that we are<br />
downloading a medium sized version of the image. Other suffixes can be found <a href="http://www.flickr.com/services/api/misc.urls.html">here</a>, which allows you to download more or less detailed versions of the images.</p>
<pre name="code" class="javascript">var imageURL:String = 'http://static.flickr.com/' + photos[currentImage].server + '/' + photos[currentImage].id + '_' + photos[currentImage].secret + '_m.jpg';</pre>
<p>Now that we&#8217;ve requested the image, we increment the currentImage variable so the next time loadNextImage is called we&#8217;ll pull down the next image in the search list.</p>
<pre name="code" class="javascript">++currentImage;
currentImage %= photos.length;</pre>
<p>Next we have to actually load the images. We create a new URLRequest object (supplying the URL that we created above to the constructor), a new Loader object, and attach the switchImages function to the Loaders Event.COMPLETE event.</p>
<pre name="code" class="javascript">var request:URLRequest = new URLRequest(imageURL);
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, switchImages);</pre>
<p>Finally, we load the image from Flickr by calling the Loaders load function.</p>
<pre name="code" class="javascript">loader.load(request); </pre>
<h2>Step 14: switchImages Function</h2>
<p>The switchImages function is called when we&#8217;ve loaded an new image from Flickr.</p>
<pre name="code" class="javascript">private function switchImages(event:Event):void
{
	displayImage = event.currentTarget.content;
	displayImage.smoothing = true;
	displayImage.width = this.width;
	displayImage.height = this.height;
	displayImage.alpha = 0;
	this.addChild(new DisplayObjectUIComponent(displayImage));

	TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
	if (backgroundImage != null)
		TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});
}</pre>
<p>The Bitmap object that is returned by the loading process is saved in the displayImage variable.</p>
<pre name="code" class="javascript">displayImage = event.currentTarget.content;</pre>
<p>This new Bitmap is then initialized so that it is smoothed (to help with the pixelization that can occur when you scale up small images), resized to fill the window, and set to be completely transparent by setting it&#8217;s alpha to 0.</p>
<pre name="code" class="javascript">displayImage.smoothing = true;
displayImage.width = this.width;
displayImage.height = this.height;
displayImage.alpha = 0;</pre>
<p>We then add the Bitmap to the Application via a new instance of the DisplayObjectUIComponent class that we described in Step 4.</p>
<pre name="code" class="javascript"> this.addChild(new DisplayObjectUIComponent(displayImage));</pre>
<p>At this point we have the new image added as a child of the Application object. It isn&#8217;t visible though because we&#8217;ve set the alpha to 0. What we want to do is fade this new image into view by increasing it&#8217;s alpha value, while at the same time fading out the last image by decreasing it&#8217;s alpha value. This is where the TweenMax library comes in. We make a call to the TweenMax.to function, and TweenMax then takes care of modifing the alpha values for us.</p>
<p>By setting the onComplete parameter to imageTweenComplete we schedule the imageTweenComplete function to be called once this tweening operation is<br />
compete.</p>
<p>We do need to check if the backgroundImage variable is null because when the first image is loaded there is no existing backgroundImage that it is displaying on top of.</p>
<pre name="code" class="javascript">TweenMax.to(displayImage, TRANSITION_TIME, {alpha:1, ease:Linear, onComplete:imageTweenComplete});
if (backgroundImage != null)
	TweenMax.to(backgroundImage, TRANSITION_TIME, {alpha:0, ease:Linear});</pre>
<h2>Step 15: imageTweenComplete Function</h2>
<p>The imageTweenComplete function is called when a newly loaded image has been faded into view by TweenMax.</p>
<pre name="code" class="javascript">private function imageTweenComplete():void
{
	if (backgroundImage != null)
	this.removeChild(backgroundImage.parent);
	backgroundImage = displayImage;
	displayImage = null;

	TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);
}</pre>
<p>Once the displayImage has been faded in, the backgroundImage is removed from the application and the displayImage becomes the backgroundImage. The<br />
displayImage is then set to null.</p>
<pre name="code" class="javascript">if (backgroundImage != null)
	this.removeChild(backgroundImage.parent);
backgroundImage = displayImage;
displayImage = null;</pre>
<p>We then use TweenMax to schedule a call to the loadNextImage function. This starts the cycle of loading a new image and fading it in again.</p>
<pre name="code" class="javascript">TweenMax.delayedCall(DISPLAY_TIME, loadNextImage);</pre>
<h2>Conclusion</h2>
<p>Using Flickr with Flash does require a few steps, but once you get your head around the Flickr API, finding out the Flickr image URLs, loading the images from Flickr (taking the Flash security restrictions into consideration) it&#8217;s then quite easy to use these images to create an appealing photo album.</p>
<p>This particular example could be used to add an animated photo album to a web page, and by changing the SEARCH_STRING variable you can display different types of images. You could even pass FlashVars to the Flash applet to determine which images are displayed without having to recompile the application. You could also modify the service.photos.search function to return only your own photos, or those that you have tagged specifically.</p>
<p>Thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/build-a-photo-viewer-using-flex-and-the-flickr-api/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>Build an AS3 Photo Slider Widget for Social Networking Sites</title>
		<link>http://active.tutsplus.com/tutorials/actionscript/build-an-as3-photo-slider-widget-for-social-networking-sites/</link>
		<comments>http://active.tutsplus.com/tutorials/actionscript/build-an-as3-photo-slider-widget-for-social-networking-sites/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 12:00:22 +0000</pubDate>
		<dc:creator>Gerb Sterrenburg</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1431</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Today we&#8217;re going to build a Photo Slider widget which can be placed on social networking sites like <a href="http://www.orkut.com/" target="_blank">Orkut</a> or <a href="http://www.myspace.com/" target="_blank">MySpace</a>. This widget will be based on Google&#8217;s Open Social API and contains a Flash application, which will show all photos from your public photo albums in a slideshow. </p>
<p>&quot;Plug-in classes&quot; will handle the transitions of the slideshow and this tutorial will include writing two of those &quot;plug-ins&quot;.</p>
<p>        <span id="more-1431"></span></p>
<div class="tutorial_image">
            <a href="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/Source.zip" target="_blank"><br />
            <img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a>
            </div>
<h2>Step 1: Things we Need</h2>
<p>In order to build and test the widget we&#8217;ll need a couple of things. I&#8217;ve listed them below:</p>
<ul>
<li>Flash CS4</li>
<li>JavaScript/PHP/XML editor (Eclipse/Aptana)</li>
<li>Some hosting space (with PHP support)</li>
<li>An account on a Social Networking site which supports OpenSocial (at least version 0.8, for this tutorial I&#8217;ll use Orkut).</li>
<li>Developer status on that Social Networking Site.</li>
</ul>
<p>For the XML/ JavaScript /PHP part of this tutorial I&#8217;ll Use Aptana, since that&#8217;s my editor of choice, but any editor will do of course. I&#8217;ve chosen Orkut because, well, Orkut is Google and OpenSocial is&#8230; Google. We need a recent version of the OpenSocial API for this tutorial (Orkut supports version 0.9).</p>
<h2>Step 2: Preparations</h2>
<p>Before we get started, we&#8217;ll need to make sure that everything is configured and set up just the way we want it. To test this widget we&#8217;ll need developer status on Orkut. Go to <a href="http://sandbox.orkut.com/SandboxSignup.aspx" target="_blank">http://sandbox.orkut.com/SandboxSignup.aspx</a> and fill in the form. You&#8217;ll get an email confirming your new status. Being a developer gives you the possibility to add widgets to your profile, which aren&#8217;t yet approved by Orkut. For security reasons these widgets are only available to you. Later on I&#8217;ll show you in more detail how to add a widget to Orkut.</p>
<p>Next, since we need a publicly available photo album, add some photos to a new album and make it public.
</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/image1.png" alt="" /></div>
<h2>Step 3: Gadget.xml</h2>
<p>We&#8217;re going to build this widget from the bottom up, so the first thing we&#8217;re going to do is write the widget&#8217;s XML file. If this is your first encounter with OpenSocial, I&#8217;d advise you to go to <a href="http://www.opensocial.org/" target="_blank">http://www.opensocial.org/</a> and read up about it. In short, OpenSocial is a framework developed by Google which can be implemented by Social Network sites making it easier for developers to build applications for them.</p>
<p>A widget generally consists of an XML file and some additional assets. This XML file and the additional assets need to be placed somewhere on a server, that&#8217;s why we need the Web space. The XML file for this widget will consist of two parts; the XML specs and the JavaScript code, which will retrieve the photos from your albums on your profile and pass them on to the Flash application.</p>
<h2>Step 4: Gadget.xml Setup</h2>
<p>The layout of the XML file is no rocket science. It contains 2 nodes, ModulePrefs and Content, which are important to us. In this step I&#8217;ll discuss the first one, ModulePrefs.</p>
<p>This node defines variables which are necessary to describe the widget. I don&#8217;t think I need to explain anything about the first ones I hope, but if you&#8217;re confused, please visit the OpenSocial website for more information.</p>
<p>The last one however, is of more importance. With this node we state that we require at least version 0.8 of the OpenSocial API or else it won&#8217;t work. For this application it&#8217;s really the only requirement we&#8217;ll need, but there are many more you can define here. Again, if you want to know more, OpenSocial.org is the place to be.</p>
<pre name="code" class="xml">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;Module&gt;
	&lt;ModulePrefs
			title=&quot;FlashTuts Widgets&quot;
			author=&quot;Gerb Sterrenburg&quot;
			author_email=&quot;gerbster@gmail.com&quot;
			description=&quot;FlashTuts Widget&quot;
			height=&quot;300&quot;
			width=&quot;400&quot;
			scaling=&quot;false&quot;
			scrolling=&quot;false&quot;
			screenshot=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/screenshot.png&quot;
			thumbnail=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/thumbnail.png&quot;&gt;
		&lt;Require feature=&quot;opensocial-0.8&quot;/&gt;
	&lt;/ModulePrefs&gt;
	&lt;Content type=&quot;html&quot;&gt;
		&lt;![CDATA[
			&lt;script type=&quot;text/javascript&quot;&gt;

				// Fetches all of the viewer's albums that are publicly viewable (i.e.
				// &quot;shared with everyone&quot;

				var masterAlbumArray = new Array();

				function fetchAlbums()
				{
					var req = opensocial.newDataRequest();
					var idspec = opensocial.newIdSpec({ &quot;userId&quot; : &quot;OWNER&quot;, &quot;groupId&quot; : &quot;SELF&quot; });

					req.add(req.newFetchAlbumsRequest(idspec), 'ownerAlbums');
					req.send(fetchAlbumsHandler);
				};

				// Callback function, executed when orkut finishes fetching the viewer's
				// public albums
				function fetchAlbumsHandler(resp)
				{
					var ownerAlbumsResp = resp.get('ownerAlbums');

					if (!ownerAlbumsResp.hadError())
					{
						var ownerAlbums = ownerAlbumsResp.getData();

						// every album is an object inside the main object 'viewerAlbums'
						// we're going to create one big album which we're gonna feed to
						// the flash application
						ownerAlbums.each(
							function(album)
							{
								addAlbumToMasterAlbum(album.getId());
							}
						);
					  }
				};

				// Fetches all photos from the album with the passed ID
				function addAlbumToMasterAlbum(albumId)
				{
				  var req = opensocial.newDataRequest();
				  var idspec = opensocial.newIdSpec({ &quot;userId&quot; : &quot;OWNER&quot;, &quot;groupId&quot; : &quot;SELF&quot; });

				  req.add(req.newFetchMediaItemsRequest(idspec, albumId), 'albumPhotos');
				  req.send(addAlbumToMasterAlbumHandler);
				};

				// Callback function, executed when orkut finishes fetching the
				// requested media items
				function addAlbumToMasterAlbumHandler(resp)
				{
					var albumPhotosResp = resp.get('albumPhotos');

					if (!albumPhotosResp.hadError())
					{
						var albumPhotos = albumPhotosResp.getData();

						albumPhotos.each(
							function(photo)
							{
								masterAlbumArray.push(photo.getField('url'));
							}
						);

						// now that all the Photo's are in
						// the masterAlbum, launch the Flash App

						launchFlashApp();
					}
				};

				// show the flash app
				function launchFlashApp()
				{
					var content = '&lt;embed src=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/widget.swf&quot; width=&quot;400&quot; height=&quot;300&quot; quality=&quot;high&quot; bgcolor=&quot;000000&quot; pluginspage=&quot;http://www.macromedia.com/go/getflashplayer&quot; allowScriptAccess=&quot;always&quot; flashvars=&quot;&quot; type=&quot;application/x-shockwave-flash&quot;&gt;';  

					document.getElementById(&quot;flashTutsWidgetDiv&quot;).innerHTML = content;
				};

				function retrieveMasterAlbum()
				{
					return masterAlbumArray;
				};

				// Execute fetchAlbums function when gadget loads
				gadgets.util.registerOnLoadHandler(fetchAlbums);
			  &lt;/script&gt;

			  &lt;div id=&quot;flashTutsWidgetDiv&quot; style=&quot;width:380;height:400&quot;&gt;&lt;img src=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/loader.gif&quot; /&gt; Loading...&lt;/div&gt;

			]]&gt;
	  &lt;/Content&gt;
&lt;/Module&gt;
		</pre>
<h2>Step 5: Gadget.xml JavaScript</h2>
<p>Now we&#8217;re getting to the really interesting part of the XML file, the content node. As mentioned above, OpenSocial is an API written in JavaScript to give developers access to all kinds of data inside a Social Network site.</p>
<p>For this widget we&#8217;re going to use some functionality concerning photo albums and media items. I&#8217;ll give you the code first and them we&#8217;ll go through it step by step.</p>
<pre name="code" class="javascript">
// Fetches all of the viewer's albums that are publicly viewable (i.e.
// &quot;shared with everyone&quot;

var masterAlbumArray = new Array();

function fetchAlbums()
{
	var req = opensocial.newDataRequest();
	var idspec = opensocial.newIdSpec({ &quot;userId&quot; : &quot;OWNER&quot;, &quot;groupId&quot; : &quot;SELF&quot; });

	req.add(req.newFetchAlbumsRequest(idspec), 'ownerAlbums');
	req.send(fetchAlbumsHandler);
};

// Callback function, executed when orkut finishes fetching the viewer's
// public albums
function fetchAlbumsHandler(resp)
{
	var ownerAlbumsResp = resp.get('ownerAlbums');

	if (!ownerAlbumsResp.hadError())
	{
		var ownerAlbums = ownerAlbumsResp.getData();

		// every album is an object inside the main object 'viewerAlbums'
		// we're going to create one big album which we're gonna feed to
		// the flash application
		ownerAlbums.each(
			function(album)
			{
				addAlbumToMasterAlbum(album.getId());
			}
		);
	  }
};

// Fetches all photos from the album with the passed ID
function addAlbumToMasterAlbum(albumId)
{
  var req = opensocial.newDataRequest();
  var idspec = opensocial.newIdSpec({ &quot;userId&quot; : &quot;OWNER&quot;, &quot;groupId&quot; : &quot;SELF&quot; });

  req.add(req.newFetchMediaItemsRequest(idspec, albumId), 'albumPhotos');
  req.send(addAlbumToMasterAlbumHandler);
};

// Callback function, executed when orkut finishes fetching the
// requested media items
function addAlbumToMasterAlbumHandler(resp)
{
	var albumPhotosResp = resp.get('albumPhotos');

	if (!albumPhotosResp.hadError())
	{
		var albumPhotos = albumPhotosResp.getData();

		albumPhotos.each(
			function(photo)
			{
				masterAlbumArray.push(photo.getField('url'));
			}
		);

		// now that all the Photo's are in
		// the masterAlbum, launch the Flash App

		launchFlashApp();
	}
};

// show the flash app
function launchFlashApp()
{
	var content = '&lt;embed src=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/widget.swf&quot; width=&quot;400&quot; height=&quot;300&quot; quality=&quot;high&quot; bgcolor=&quot;000000&quot; pluginspage=&quot;http://www.macromedia.com/go/getflashplayer&quot; allowScriptAccess=&quot;always&quot; flashvars=&quot;&quot; type=&quot;application/x-shockwave-flash&quot;&gt;';  

	document.getElementById(&quot;flashTutsWidgetDiv&quot;).innerHTML = content;
};

function retrieveMasterAlbum()
{
	return masterAlbumArray;
};

// Execute fetchAlbums function when gadget loads
gadgets.util.registerOnLoadHandler(fetchAlbums);
</pre>
<p>The general idea behind this piece of code is not very complex. We&#8217;ll define an array, which we fill with the URL&#8217;s of all the photos in the publically accessible albums. If this is done, we&#8217;ll show the Flash application, which will then retrieve the array we&#8217;ve just made.</p>
<h2>Step 6: Retrieving Albums</h2>
<p>To retrieve all the photo albums from the profile, we&#8217;ll need two functions. One that will perform the call and one that will handle the result when it comes back from the call.</p>
<p>Caller:</p>
<pre name="code" class="javascript">
function fetchAlbums()
{
	var req = opensocial.newDataRequest();
	var idspec = opensocial.newIdSpec({ "userId" : "OWNER", "groupId" : "SELF" });

	req.add(req.newFetchAlbumsRequest(idspec), 'ownerAlbums');
	req.send(fetchAlbumsHandler);
};
		</pre>
<p>Handler:</p>
<pre name="code" class="javascript">
// Callback function, executed when orkut finishes fetching the viewer's
// public albums
function fetchAlbumsHandler(resp)
{
	var ownerAlbumsResp = resp.get('ownerAlbums');

	if (!ownerAlbumsResp.hadError())
	{
		var ownerAlbums = ownerAlbumsResp.getData();

		// every album is an object inside the main object 'viewerAlbums'
		// we're going to create one big album which we're gonna feed to
		// the flash application
		ownerAlbums.each(
			function(album)
			{
				addAlbumToMasterAlbum(album.getId());
			}
		);
	}
};
		</pre>
<p>I don&#8217;t want to go to into too much depth here concerning OpenSocial, since it is not the main subject of this tutorial. But to give you some clues about what&#8217;s happening here, I&#8217;ll explain it in general terms.</p>
<p>In the OpenSocial environment you&#8217;ll have 2 roles, namely &#8216;owner&#8217; and &#8216;viewer&#8217;. Needless to say, the owner is the actual owner of the profile, then the viewer, well that&#8217;s the person who&#8217;s visiting. If you&#8217;re going to request some data, you&#8217;ll need to specify whose data you want; the viewer&#8217;s or the owner&#8217;s.</p>
<p>Next, if you perform a request, you&#8217;ll need to specify a handler. This handler will be executed when the data comes back from the server. So here we request all the albums belonging to the owner&#8217;s profile and when the data comes back from the server, we&#8217;ll fetch all the photos from them.</p>
<h2>Step 7: Retrieving the Photos</h2>
<p>This step is very similar to the previous one. For every album we get back, we&#8217;ll call a function to retrieve the items in it. Next, those items will be added to our array, which will be retrieved by the flash application later on. </p>
<pre name="code" class="javascript">
// Fetches all photos from the album with the passed ID
function addAlbumToMasterAlbum(albumId)
{
	var req = opensocial.newDataRequest();
	var idspec = opensocial.newIdSpec({ "userId" : "OWNER", "groupId" : "SELF" });

	req.add(req.newFetchMediaItemsRequest(idspec, albumId), 'albumPhotos');
	req.send(addAlbumToMasterAlbumHandler);
};
		</pre>
<p>Handler:</p>
<pre name="code" class="javascript">
// Callback function, executed when orkut finishes fetching the
// requested media items
function addAlbumToMasterAlbumHandler(resp)
{
	var albumPhotosResp = resp.get('albumPhotos');

	if (!albumPhotosResp.hadError())
	{
		var albumPhotos = albumPhotosResp.getData();

		albumPhotos.each(
			function(photo)
			{
				masterAlbumArray.push(photo.getField('url'));
			}
		);

		// now that all the Photo's are in
		// the masterAlbum, launch the Flash App

		launchFlashApp();
	}
};
		</pre>
<p>Note: we&#8217;re only getting the URL from the photo object, but there&#8217;s more. For a full list of all the properties you can retrieve, like comments and statistics, go to opensocial.org. </p>
<h2>Step 8: Placing the Flash App on the Screen</h2>
<p>The last line of the handler function described above calls for the function &quot;launchFlashApp&quot;.</p>
<pre name="code" class="javascript">
launchFlashApp();</pre>
<p>This does exactly what the name implies, it places the flash application inside the div tag defined at the bottom of the content node. When it&#8217;s loaded, the flash application will call the function &#8220;retrieveMasterAlbum&#8221;.</p>
<pre name="code" class="javascript">
// show the flash app
function launchFlashApp()
{
	var content = '&lt;embed src=&quot;http://85.17.135.135/~gerbster/projects/FlashTutsWidget/widget.swf&quot; width=&quot;400&quot; height=&quot;300&quot; quality=&quot;high&quot; bgcolor=&quot;000000&quot; pluginspage=&quot;http://www.macromedia.com/go/getflashplayer&quot; allowScriptAccess=&quot;always&quot; flashvars=&quot;&quot; type=&quot;application/x-shockwave-flash&quot;&gt;';  

	document.getElementById(&quot;flashTutsWidgetDiv&quot;).innerHTML = content;
};
		</pre>
<p>The last line of this javascript part will call the fetchAlbums function when the widget is fully loaded.</p>
<pre name="code" class="javascript">
// Execute fetchAlbums function when gadget loads
gadgets.util.registerOnLoadHandler(fetchAlbums);
		</pre>
<h2>Step 9: Proxy.php</h2>
<p>Now that the XML file is ready, we&#8217;ll need to do one more thing before we can start with the flash part of the tutorial. The security restrictions of the flash player prevent it from accessing the bitmap data of an image loaded from another domain. Since we need that bitmap data for the effects we&#8217;re going to add later on, we need a solution for this problem. The solution comes in the form of a little piece of PHP. This script will act as a proxy between the social media site and our flash application.</p>
<p>It&#8217;s really simple, just pass a URL to this script and it will retrieve and display the content of that URL. This way, the flash application will think that the image comes from our own server and we don&#8217;t have to worry about the security restriction.</p>
<pre name="code" class="javascript">
&lt;?php

	$post_data = $HTTP_RAW_POST_DATA;

	$header[] = &quot;Content-type: text/xml&quot;;
	$header[] = &quot;Content-length: &quot;.strlen($post_data);

	preg_match(&quot;/url=(.*)/&quot;,$_SERVER['REQUEST_URI'],$params);

	$ch = curl_init( $params[1] );

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
	curl_setopt($ch, CURLOPT_TIMEOUT, 10);
	curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

	if ( strlen($post_data)&gt;0 )
	{
	    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
	}

	$response = curl_exec($ch);     

	if (curl_errno($ch))
	{
	    print curl_error($ch);
	}
	else
	{
	    curl_close($ch);
	    header(&quot;Content-type: text/xml; Content-length: &quot;.strlen($response));
	    print $response;
	}

?&gt;
		</pre>
<p>Since this tutorial is not about PHP I&#8217;ve taken the liberty of using an existing script. It&#8217;s written by Abdul Qabiz and it does exactly what we want, so no need to reinvent the wheel. More information about this script <a href="http://www.abdulqabiz.com/blog/archives/2007/05/31/php-proxy-script-for-cross-domain-requests/" target="_blank">can be found here</a>..</p>
<p>..and more information about the security restriction <a href="http://www.untoldentertainment.com/blog/?p=24" target="_blank">can be found here</a>.</p>
<h2>Step 10: Flash &#8211; Introduction</h2>
<p>As mentioned above, the flash application will show all the photos in a slideshow and &quot;plug-in classes&quot; will perform the transitions.  The first thing we need to do is to set up a new Flash project and assign its base class. I don&#8217;t want to go into the details too much, because I presume this is not the first flash application you&#8217;ve built.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/image2.png" alt="" /></div>
<h2>Step 11: Flash &#8211; Base Class</h2>
<p>If you downloaded the source files of this project, you&#8217;ll notice that in the root directory (the one that contains the .fla file), there&#8217;s a folder called &quot;widget&quot; and inside that folder there&#8217;s a file called &quot;Widget.as&quot;. This is going to be our base class.</p>
<p>Below, you&#8217;ll see the full code of the base class. Again, I won&#8217;t discuss every detail of it, but in the next steps I&#8217;ll highlight the most important aspects.</p>
<pre name="code" class="javascript">
package widget
{
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.net.URLRequest;
	import flash.system.*;

	import gs.TweenMax;

	import widget.transitions.*;
	import widget.OpenSocialPhotoLoader;

	public class Widget extends MovieClip
	{
		private var myProxy:String = "http://85.17.135.135/~gerbster/projects/FlashTutsWidget/proxy.php?url=";
		//private var myProxy:String = "";

		private var myOSPL:OpenSocialPhotoLoader;
		private var photoArray:Array;

		private var myPhotoLoader:Loader;
		public var myPhotoHolder:MovieClip;

		private var fadeInOutTransition:FadeInOut;
		private var cubes3DTransition:Cubes3D;
		private var transitionsArray:Array = new Array();

		private var currentPhotoIndex:Number = 0;
		private var transitionIndex:Number = NaN;

		private var photoTime:Number = 5;

		public function Widget():void
		{
			Security.allowDomain("orkut.com");

			myPhotoHolder = new MovieClip();
			myPhotoHolder.name = "photoHolder";

			addChild(myPhotoHolder);

			initPhotoArray();
			initTransitions();

			if(photoArray.length &gt; 0)
			{
				loadPhoto(currentPhotoIndex);
			}
		}

		private function initPhotoArray()
		{
			myOSPL = new OpenSocialPhotoLoader();

			addChild(myOSPL);

			myOSPL.loadAlbum();

			photoArray = myOSPL.masterAlbum;
		}

		private function initTransitions()
		{
			fadeInOutTransition = new FadeInOut();
			cubes3DTransition = new Cubes3D();

			transitionsArray.push(fadeInOutTransition);
			transitionsArray.push(cubes3DTransition);
		}

		private function loadPhoto(index:Number):void
		{
			if(index &gt;= photoArray.length)
			{
				index = 0;
			}

			if(index == -1)
			{
				index = photoArray.length;
			}

			myPhotoLoader = new Loader();
			var photoUrl:String = photoArray[index];
			var photoUrlReq:URLRequest = new URLRequest(myProxy + photoUrl);

			myPhotoLoader.load(photoUrlReq);

			// if the photo is loaded, call showNextPhoto which will do the transition
			myPhotoLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, showNextPhoto);

			// increment currentPhotoIndex and call this function again in 5 seconds
			currentPhotoIndex = ++index;
			TweenMax.delayedCall( photoTime, loadPhoto, [currentPhotoIndex]);
		}

		private function showNextPhoto(e:Event)
		{
			// we want our photo's nicely scaled and centered
			var scaleValue:Number = calculateScaleValue(e.target.loader.contentLoaderInfo.width, e.target.loader.contentLoaderInfo.height);

			var translateX:Number = (stage.stageWidth - (e.target.loader.contentLoaderInfo.width * scaleValue)) / 2;
			var translateY:Number = (stage.stageHeight - (e.target.loader.contentLoaderInfo.height * scaleValue)) / 2;

			// ...so we use a matrix
			var resizeMatrix:Matrix = new Matrix();
			resizeMatrix.scale(scaleValue, scaleValue);
			resizeMatrix.translate(translateX, translateY);

			var newPhotoBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
			newPhotoBitmapData.draw(e.target.loader, resizeMatrix, null, null, null, true);

			// if there's a photo on stage do a transition
			if(myPhotoHolder.numChildren &gt; 0)
			{
				var oldPhotoBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);

				oldPhotoBitmapData.draw(myPhotoHolder.getChildAt(0), null, null, null, null, true);

				// remove the old transition object
				if(myPhotoHolder.getChildAt(0) is ITransition)
				{
					transitionsArray[transitionIndex].destroyTransition();
				}

				// remove the old transition object
				myPhotoHolder.removeChild(myPhotoHolder.getChildAt(0));

				// pick a random transition
				transitionIndex = Math.round(Math.random() * (transitionsArray.length - 1));

				myPhotoHolder.addChild(transitionsArray[transitionIndex]);

				transitionsArray[transitionIndex].doTransition(oldPhotoBitmapData, newPhotoBitmapData);
			}
			else
			{
				var newPhoto:Bitmap = new Bitmap(newPhotoBitmapData);

				myPhotoHolder.addChildAt(newPhoto, 0);
			}
		}

		private function calculateScaleValue(oldWidth:Number, oldHeight:Number):Number
		{
			var photoRatio:Number = oldHeight / oldWidth;
			var screenRatio:Number = stage.stageHeight / stage.stageWidth;

			if(photoRatio < screenRatio)
			{
				return stage.stageWidth / oldWidth;
			}
			else
			{
				return stage.stageHeight / oldHeight;
			}
		}
	}
}
		</pre>
<h2>Step 12: Flash - Imports</h2>
<p>Before we can get anything to run, we need to import some classes. The first five are native flash classes and aren't very exciting. Next we need to import <a href="http://blog.greensock.com/tweenmaxas3/" target="_blank">TweenMax</a>. TweenMax is a commonly used tween class, but we're going to use it here because is has a delayedTask function. We'll discuss this in more detail later on. Finally we need to import the transition classes and the OpenSocialPhotoLoader class.</p>
<pre name="code" class="javascript">
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.URLRequest;
import flash.system.*;

import gs.TweenMax;

import widget.transitions.*;
import widget.OpenSocialPhotoLoader;
		</pre>
<h2>Step 13: Flash - Constructor</h2>
<p>As you probably know, the constructor will be called upon when the application starts, so here we'll do all the initializations. First we'll tell this application that Orkut.com is a safe domain. We need to do this or else we won't be able to call the javascript function to get the photo array. Next we'll add an empty MovieClip to the stage, which will act as a container for the photo's we're about to show. Thirdly, we'll call two init functions. These functions initialize the transitions and retrieve the photo array from javascript.  The last 3 lines of code will check if there any photos in the array and if so, show the first photo.</p>
<pre name="code" class="javascript">
public function Widget():void
{
	Security.allowDomain("orkut.com");

	myPhotoHolder = new MovieClip();
	myPhotoHolder.name = "photoHolder";

	addChild(myPhotoHolder);

	initPhotoArray();
	initTransitions();

	if(photoArray.length &gt; 0)
	{
		loadPhoto(currentPhotoIndex);
	}
}
		</pre>
<h2>Step 14: Flash - InitPhotoArray</h2>
<p>The initPhotoArray function will make a new instance of the OpenSocialPhotoLoader class, add to the stage, then call the loadAlbum function inside that class and finally assign the masterAlum variable inside that class to our local photoArray variable (which we declared at the top of the class). In the next step we'll discuss the OpenSocialPhotoLoader class in more detail.</p>
<pre name="code" class="javascript">
private function initPhotoArray()
{
	myOSPL = new OpenSocialPhotoLoader();

	addChild(myOSPL);

	myOSPL.loadAlbum();

	photoArray = myOSPL.masterAlbum;
}
		</pre>
<h2>Step 15: Flash - OpenSocialPhotoLoader</h2>
<p>To get the obvious question out of the way, why use a separate class to load the photos? Well, if you want to reuse this application in a different environment, you won't need to completely rewrite the base class, just build a new Loader class and implement it. Hail OOP!</p>
<p>This class is very simple though. It contains a loadAlbum function, which will use the external interface class from the AS3 library to call the retrieveMasterAlbum function from javascript. This function returns an object which contains all the URL's. Finally, all the items in that object will be added to a local Array.</p>
<pre name="code" class="javascript">
package widget
{
	import flash.external.ExternalInterface;
	import flash.display.MovieClip;

	public class OpenSocialPhotoLoader extends MovieClip
	{
		private var rawMasterAlbum:Object;
		public var masterAlbum:Array = new Array();

		public function OpenSocialPhotoLoader()
		{
		}

		public function loadAlbum():void
		{
			if (ExternalInterface.available)
			{
				try
				{
					rawMasterAlbum = ExternalInterface.call("retrieveMasterAlbum");

					for each (var value:* in rawMasterAlbum)
					{
						masterAlbum.push(value.toString());
					}
				}
				catch (error:SecurityError)
				{

				}
				catch (error:Error)
				{

				}
			}
			else
			{

			}
		}
	}
}
		</pre>
<p>Since calling a function from javascript is prone to all kinds of errors, we'll use a try catch construction here. </p>
<h2>Step 16: Flash - initTransitions</h2>
<p>Let's get back to our base class. After initializing the photo array, we're going to initialize the various transitions we'll build later on. In the top of this class we've declared two transitions and a transition array. What we do here is very simple; make an instance of the transition class and push it into the array.</p>
<pre name="code" class="javascript">
private function initTransitions()
{
	fadeInOutTransition = new FadeInOut();
	cubes3DTransition = new Cubes3D();

	transitionsArray.push(fadeInOutTransition);
	transitionsArray.push(cubes3DTransition);
}
		</pre>
<p>Why we do this, I'll tell you later on.</p>
<h2>Step 17: Flash - loadPhoto</h2>
<p>The last 3 lines of the constructor were responsible for &quot;kick starting&quot; the application. If there are any photos in the array, loadPhoto is called with currentPhotoIndex as its argument. The variable currentPhotoIndex is declared at the top of the class and it holds the index number of the current photo on the screen. It's declared with default value 0. Let's examine the function and then discuss it. </p>
<pre name="code" class="javascript">
private function loadPhoto(index:Number):void
{
	if(index &gt;= photoArray.length)
	{
		index = 0;
	}

	if(index == -1)
	{
		index = photoArray.length;
	}

	myPhotoLoader = new Loader();
	var photoUrl:String = photoArray[index];
	var photoUrlReq:URLRequest = new URLRequest(myProxy + photoUrl);

	myPhotoLoader.load(photoUrlReq);

	// if the photo is loaded, call showNextPhoto which will do the transition
	myPhotoLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, showNextPhoto);

	// increment currentPhotoIndex and call this function again in 5 seconds
	currentPhotoIndex = ++index;
	TweenMax.delayedCall( photoTime, loadPhoto, [currentPhotoIndex]);
}
		</pre>
<p>The first two <em>if</em> statements will check if the currentPhotoIndex  is out of bounds and if so, correct it. The next step will be actually loading the picture.  We use our proxy script here to bypass the flash security restriction. The myProxy string is also declared at the top of the class. We'll add an eventListener to this loader, which will execute the showNextPhoto function in the event that the photo is fully loaded.</p>
<p>As a final step we'll increase the currentPhotoIndex and use the TweenMax delayedCall function to re-call this function in 5 seconds. More information about the delayedCall function can be found on the homepage of TweenMax: <a href="http://blog.greensock.com/tweenmaxas3/" target="_blank">http://blog.greensock.com/tweenmaxas3/</a>.</p>
<h2>Step 18: Flash - ShowNextPhoto</h2>
<p>This function is the most important function of them all. In short, it will resize and position the loaded photo correctly, hand it down to the transitions classes, then finally make sure it's visible on the screen. This function is called when a photo is fully loaded. I'll break this function down into 4 parts.</p>
<p><em><b>Editor's Note:</b> As occasionally happens, something within this showNextPhoto function didn't want to play nicely with our syntax highlighter. As it won't display on the page, I've made the function <a href="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/showNextPhoto.as" target="_blank">available for download</a>. Sorry for any inconvenience, Ian.</em></p>
<p>The first thing we're going to do is to rescale the image and position it correctly. No matter what the dimensions of the photo are, it's being centered and placed on a black background. To do this we use a matrix. Although it may seem scary at first, using a matrix is very efficient and not that difficult. More information on matrixes can be found in the AS3 API on adobe.com. We use a small function called calculateScaleValue to determine the scale factor we need for resizing the photo.</p>
<pre name="code" class="javascript">
if(myPhotoHolder.numChildren &gt; 0)
		</pre>
<p>Next we'll determine if there are any pictures on the screen yet. We need to do this because the first picture needs to be shown directly without a transition (there's nothing to transition from). </p>
<pre name="code" class="javascript">
if(myPhotoHolder.numChildren &gt; 0)
{
	var oldPhotoBitmapData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);

	oldPhotoBitmapData.draw(myPhotoHolder.getChildAt(0), null, null, null, null, true);

	// remove the old transition object
	if(myPhotoHolder.getChildAt(0) is ITransition)
	{
		transitionsArray[transitionIndex].destroyTransition();
	}

	// remove the old transition object
	myPhotoHolder.removeChild(myPhotoHolder.getChildAt(0));

	// pick a random transition
	transitionIndex = Math.round(Math.random() * (transitionsArray.length - 1));

	myPhotoHolder.addChild(transitionsArray[transitionIndex]);

	transitionsArray[transitionIndex].doTransition(oldPhotoBitmapData, newPhotoBitmapData);
}
		</pre>
<p>However, if there's a picture already, we first need to remove the old transition object, then pick a new one from the transitions array by using the random function, add this to the screen and finally order the transition class to &quot;doTransition&quot;. As arguments we feed the old, current bitmap data and the new bitmap data. Note here that we use the ITransition interface to check if the child on stage is a transition class or not. More information about this interface will come in a few steps.</p>
<pre name="code" class="javascript">
else
{
	var newPhoto:Bitmap = new Bitmap(newPhotoBitmapData);

	myPhotoHolder.addChildAt(newPhoto, 0);
}
		</pre>
<p>If not, we just put the photo on the screen.</p>
<h2>Step 19: Flash - The Transition Plugins</h2>
<p>As mentioned earlier, the transition effects are being handled by plug-ins. The plug-ins are classes, which implement an interface called ITransition and will handle the visual transition from the old photo to the new.  I've made two of these classes, one simple fade in/fade out transition and a complex one, which shows 3d rotating cubes. In the next few steps we'll discuss this interface and the 2 transitions.</p>
<h2>Step 20: Flash - The interface</h2>
<p>If this is your first encounter with an interface, I'd advise you to search the web and read up about it. In short, an interface is an OOP concept and it defines some specifications for the various plug-in classes. We'll use it here to make sure that our transition classes include certain functions. The code of this interface is very simple:</p>
<pre name="code" class="javascript">
package widget.transitions
{
	import flash.display.*;	

	public interface ITransition
	{
		function doTransition(oldPhotoBitmapData:BitmapData, newPhotoBitmapData:BitmapData):void;

		function destroyTransition():void
	}
}
		</pre>
<p>Both our transition classes will implement this interface, so both will need to have a doTransition and a destroyTransition function or else we'll get compiler errors. Next to that, we'll use this interface to check if an object inside the photo container on the stage is a transition class.</p>
<h2>Step 21: Flash - The FadeInOut class</h2>
<p>The first of our two transition classes is a fade in fade out effect. It's a simple class, which extends the MovieClip class (because we're adding it as a child to our photo container in the base class) and it implements the ITransition interface. It's doTransition function will place both photos on the screen, make the new one transparent and with the use of TweenMax fade it in and out . This takes 1 second, which is defined by the variable playtime in the top of the class.</p>
<pre name="code" class="javascript">
package widget.transitions
{
	import flash.display.*;

	import gs.TweenMax;
	import gs.easing.*;	

	public class FadeInOut extends MovieClip implements ITransition
	{
		// playtime in seconds
		public var playTime:Number = 1;

		public function FadeInOut()
		{
		}

		public function doTransition(oldPhotoBitmapData:BitmapData, newPhotoBitmapData:BitmapData):void
		{
			var oldPhoto:Bitmap = new Bitmap(oldPhotoBitmapData);
			this.addChild(oldPhoto);

			var newPhoto:Bitmap = new Bitmap(newPhotoBitmapData);
			newPhoto.alpha = 0;
			this.addChild(newPhoto);	

			TweenMax.to(oldPhoto, playTime, {alpha: 0, ease:Quad.easeIn});
			TweenMax.to(newPhoto, playTime, {alpha: 1, ease:Quad.easeOut});
		}

		public function destroyTransition():void
		{
			// no need to destroy anything.
		}
	}
}
		</pre>
<p>Since there is no real need to do anything after the transition is done the destroyTransition function is left empty. We could use it to remove the old photo from the stage but since that has no effect on the performance we just leave it this way.  Remember we have to implement it, because of the interface we use.</p>
<h2>Step 22: Flash - The Cubes3D class</h2>
<p>The second transition class is somewhat more complex then the previous one. It will show a grid of rotating cubes. These cubes will have both photos as textures. To create this effect we'll use papervision3d.</p>
<p>Again, the class will extend the MovieClip and implements the ITransition interface. In addition to the doTranstion and destroyTransition functions there are some other functions. I'll discuss them in the next several steps. The complete code of this transition class looks like this:</p>
<pre name="code" class="javascript">
package widget.transitions
{
	import flash.display.*;
	import flash.events.*
	import flash.geom.*;

	import org.papervision3d.materials.*;
	import org.papervision3d.materials.utils.*;
	import org.papervision3d.objects.primitives.Cube;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;	

	import gs.TweenMax;
	import gs.easing.*;		

	public class Cubes3D extends MovieClip implements ITransition
	{
		private var viewport:Viewport3D; // The Viewport
		private var renderer:BasicRenderEngine; // Rendering engine
		private var scene:Scene3D; // A Scene
		private var camera:Camera3D;		

		private var cubeSize:Number = 100;
		private var horizontalAmount:Number = 4;
		private var verticalAmount:Number = 3;

		public function Cubes3D()
		{
		}

		public function doTransition(oldPhotoBitmapData:BitmapData, newPhotoBitmapData:BitmapData):void
		{
			init3d();

			for(var v:int = 0; v < verticalAmount; v++)
			{
				for(var h:int = 0; h < horizontalAmount; h++)
				{
					var oldPhotoPart:BitmapData = new BitmapData(cubeSize, cubeSize);
					oldPhotoPart.copyPixels(oldPhotoBitmapData ,new Rectangle(h*cubeSize, v*cubeSize, cubeSize, cubeSize), new Point(0,0));

					var newPhotoPart:BitmapData = new BitmapData(cubeSize, cubeSize);
					newPhotoPart.copyPixels(newPhotoBitmapData ,new Rectangle(h*cubeSize, v*cubeSize, cubeSize, cubeSize), new Point(0,0));					

					var frontMaterial:BitmapMaterial = new BitmapMaterial(oldPhotoPart);
					var backMaterial:BitmapMaterial = new BitmapMaterial(newPhotoPart);

					var ml:MaterialsList = new MaterialsList({
																front:	frontMaterial,
																right:	new ColorMaterial(0x000000, 0),
																left:	new ColorMaterial(0x000000, 0),
																back:   backMaterial,
																top:    new ColorMaterial(0x000000, 0),
																bottom: new ColorMaterial(0x000000, 0)
															});					

					var cube:Cube = new Cube(ml, cubeSize, cubeSize, cubeSize, 4, 4, 4);

					cube.name = "cube_"+v+"_"+h;

					cube.x = -(h * cubeSize) + (stage.stageWidth / 2) - (cubeSize / 2);
					cube.y = -(v * cubeSize) + (stage.stageHeight / 2) - (cubeSize / 2);

					scene.addChild(cube);
				}
			}

			// cubes are loaded, so start rotating!
			for(var i:int = 0; i &lt; verticalAmount; i++)
			{
				for(var j:int = 0; j &lt; horizontalAmount; j++)
				{
					var cubeNumber:Number = i*verticalAmount + j;

					viewport.getChildLayer(scene.getChildByName("cube_"+i+"_"+j), true).layerIndex = cubeNumber;

					 but not all at once, so use a delayedcall
					TweenMax.delayedCall(cubeNumber/10, rotateCube, ["cube_"+i+"_"+j]);
				}
			}
		}

		private function rotateCube(cubeName:String)
		{
			TweenMax.to(scene.getChildByName(cubeName), 0.75, {rotationY: -180, ease:Linear.easeNone, onComplete: sortLayers, onCompleteParams: [cubeName]});
		}

		private function sortLayers(cubeName:String)
		{
			viewport.getChildLayer(scene.getChildByName(cubeName), true).layerIndex = 1;
		}

		private function init3d()
		{
			viewport = new Viewport3D(stage.stageHeight, stage.stageWidth, true);
			renderer = new BasicRenderEngine();
			scene = new Scene3D();
			camera = new Camera3D();

			var cameraPoint:DisplayObject3D = new DisplayObject3D();

			cameraPoint.x = 0;
			cameraPoint.y = 0;
			cameraPoint.z = 0;

			camera.z = 2450;
			camera.zoom = 120;
			camera.focus = 20;

			camera.target = cameraPoint;

			addEventListener(Event.ENTER_FRAME, render);

			addChild(viewport);
		}

		private function render(e:Event):void
		{
			renderer.renderScene(scene, camera, viewport);
		}

		public function destroyTransition():void
		{
			removeEventListener(Event.ENTER_FRAME, render);

			removeChild(viewport);

			viewport = null;
			renderer = null;
			scene = null;
			camera = null;
			cameraPoint = null;
		}
	}
}
		</pre>
<h2>Step 23: Flash - Cubes3D - init3d</h2>
<p>The first step of the doTransition function is to call the init3d function. This function initializes the various components needed by papervision3d. No rocket science here. To flatten the 3d effect, we place the camera at some distance and use the zoom property to zoom in on the cubes. Next we'll add an event listener which renders the whole scene.</p>
<pre name="code" class="javascript">
private function init3d()
{
	viewport = new Viewport3D(stage.stageHeight, stage.stageWidth, true);
	renderer = new BasicRenderEngine();
	scene = new Scene3D();
	camera = new Camera3D();

	var cameraPoint:DisplayObject3D = new DisplayObject3D();

	cameraPoint.x = 0;
	cameraPoint.y = 0;
	cameraPoint.z = 0;

	camera.z = 2450;
	camera.zoom = 120;
	camera.focus = 20;

	camera.target = cameraPoint;

	addEventListener(Event.ENTER_FRAME, render);

	addChild(viewport);
}
		</pre>
<h2>Step 24: Flash - Cubes3D - doTransition </h2>
<p>When papervision3d is correctly initialized, the doTransition function continues and it will place a total of 12 cubes in the 3d scene. These cubes all have a part of the old photo and the new photo on their front and back. These pieces fit together as a puzzle.  To identify the individual cubes they all get a name that gives away their position in the grid.</p>
<pre name="code" class="javascript">
public function doTransition(oldPhotoBitmapData:BitmapData, newPhotoBitmapData:BitmapData):void
{
	init3d();

	for(var v:int = 0; v &lt; verticalAmount; v++)
	{
		for(var h:int = 0; h &lt; horizontalAmount; h++)
		{
			var oldPhotoPart:BitmapData = new BitmapData(cubeSize, cubeSize);
			oldPhotoPart.copyPixels(oldPhotoBitmapData ,new Rectangle(h*cubeSize, v*cubeSize, cubeSize, cubeSize), new Point(0,0));

			var newPhotoPart:BitmapData = new BitmapData(cubeSize, cubeSize);
			newPhotoPart.copyPixels(newPhotoBitmapData ,new Rectangle(h*cubeSize, v*cubeSize, cubeSize, cubeSize), new Point(0,0));					

			var frontMaterial:BitmapMaterial = new BitmapMaterial(oldPhotoPart);
			var backMaterial:BitmapMaterial = new BitmapMaterial(newPhotoPart);

			var ml:MaterialsList = new MaterialsList({
														front:	frontMaterial,
														right:	new ColorMaterial(0x000000, 0),
														left:	new ColorMaterial(0x000000, 0),
														back:   backMaterial,
														top:    new ColorMaterial(0x000000, 0),
														bottom: new ColorMaterial(0x000000, 0)
													});					

			var cube:Cube = new Cube(ml, cubeSize, cubeSize, cubeSize, 4, 4, 4);

			cube.name = "cube_"+v+"_"+h;

			cube.x = -(h * cubeSize) + (stage.stageWidth / 2) - (cubeSize / 2);
			cube.y = -(v * cubeSize) + (stage.stageHeight / 2) - (cubeSize / 2);

			scene.addChild(cube);
		}
	}
		</pre>
<p>Next, we'll start rotating them. Again we use the delayedCall function of TweenMax to add a little delay in order to get a sweeping effect.</p>
<pre name="code" class="javascript">
	// cubes are loaded, so start rotating!
	for(var i:int = 0; i &lt; verticalAmount; i++)
	{
		for(var j:int = 0; j &lt; horizontalAmount; j++)
		{
			var cubeNumber:Number = i*verticalAmount + j;

			viewport.getChildLayer(scene.getChildByName("cube_"+i+"_"+j), true).layerIndex = cubeNumber;

			// but not all at once, so use a delayedcall
			TweenMax.delayedCall(cubeNumber/10, rotateCube, ["cube_"+i+"_"+j]);
		}
	}
}
		</pre>
<p>When the rotation is done, we'll call the sortLayers function to make sure the cubes are layered correctly.</p>
<pre name="code" class="javascript">
private function sortLayers(cubeName:String)
{
	viewport.getChildLayer(scene.getChildByName(cubeName), true).layerIndex = 1;
}
		</pre>
<h2>Step 25: Flash - Cubes3D - destroyTransition</h2>
<p>In contrast to the fade in/out class we'll need to do something with destroyTransition function here. We'll use it to remove the event listener that handles the rendering and the various other papervision3d components. Why? Well if we don't do this the performance of the application will drop dramatically every time this transition is used. Since the transition object isn't destroyed in the base class when it finishes, it will create a new papervision3d environment every time it's called, causing serious performance issues.</p>
<pre name="code" class="javascript">
public function destroyTransition():void
{
	removeEventListener(Event.ENTER_FRAME, render);

	removeChild(viewport);

	viewport = null;
	renderer = null;
	scene = null;
	camera = null;
	cameraPoint = null;
}
		</pre>
<h2>Step 26: Putting it all online.</h2>
<p>Now that we have everything in place, it's time to put it all online. Make sure that all the paths inside the widget.xml file and the path to proxy script inside the base class are correct.</p>
<p>After uploading then testing the proxy script and flash application it's time to add your widget to your Orkut profile. To do this, navigate to Orkut.com, login and navigate to: <a href="http://sandbox.orkut.com/" target="_blank">http://sandbox.orkut.com/</a>. Make sure that you have developer status. While you're in the sandbox, you have the ability to add your own applications. To do this, click on &quot;edit&quot; next to &quot;Apps&quot; in the left column and you will see an extra input field. Fill in the URL of your widget.xml file, press &quot;add application&quot; and you're done.</p>
<p>If everything is correct you'll see a very nice photo slider!</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/image3.png" alt="" /></div>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/075_SocialWidget/image4.png" alt="" /></div>
<h2>Final Note.</h2>
<p>As a final word, I want to give you some tips concerning building and testing OpenSocial applications. To make things somewhat easier, the OpenSocial community just released a tool called OpenSocial Development Environment (OSDE) in which you can simulate a social network site (it's a plug-in for Eclipse). However, to this day it only supports OpenSocial API version 0.7, which was not enough for this tutorial.</p>
<p>To debug the javascript part of an application you can use a built-in function called Gadgets.util.log, which is in essence just a wrapper for console.log (firebug / firefox).</p>
<p>In order to test your flash application, it can be handy to use a different PhotoLoader class. One that just loads an array of pictures from your HD, because believe me, you don't want to upload the xml file and flash app everytime you want to test if an transition works properly <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Thanks for reading, I hope you learned something!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/actionscript/build-an-as3-photo-slider-widget-for-social-networking-sites/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Creating a Feed Reader Widget with Adobe Flex 3</title>
		<link>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/</link>
		<comments>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/#comments</comments>
		<pubDate>Wed, 22 Jul 2009 12:00:22 +0000</pubDate>
		<dc:creator>Mario Santos</dc:creator>
				<category><![CDATA[Flex]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1202</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial you&#8217;ll learn how to create your own Flex feed reader application. In this case, the final result will be a simple feed reader which can be used in your blog or site to display your favorite feeds.</p>
<p><span id="more-1202"></span> </p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Pre-Requirements</h2>
<p>To complete this tutorial you&#8217;ll need some things:</p>
<ul>
<li>A copy of Flex Builder 3.x, you can download a trial for free <a href="http://www.adobe.com/products/flex/" title="adobe.com">from the Adobe site</a>.</li>
<li>The opensource library <b>as3syndicationlib</b> (I won&#8217;t re-invent the wheel by creating one syndication lib!) which can be downloaded <a href="http://code.google.com/p/as3syndicationlib/downloads/list/" title="as3syndicationlib at google code!">here</a>.</li>
<li>Images I&#8217;ve used in the project. You can download them <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/images.zip" title="Project Images">here</a>.</li>
<li>The <a href="XMLUtil.zip" title="XMLUtil class">XMLUtil.as</a> class to validate XML Structure, available from <a href="http://code.google.com/p/as3corelib/" title="coreLib google page">corelib Package</a>.</li>
<li>Some free time!</li>
</ul>
<h2>Step 1: Create a New Project</h2>
<p>Well, this is probably something that you already know how to do, but just to remind you and ensure we&#8217;re working on the same page:</p>
<p>Begin by running Flex Builder then create a new project (Menu File &gt; New &gt; Flex Project). Make sure you enter the same properties in the dialog as shown here:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/1.jpg" alt="Creating a new Project" width="600" height="328" /></div>
<p>Just enter as the Project name: <b>WFlexibleFeed</b>. All the rest remains like it is! Press the &#8220;finish&#8221; button! Your project is created!</p>
<h2>Step 2: Setting up Required Libs</h2>
<p>Open the downloaded xmlsyndication-.85.zip lib from the provided <a href="http://code.google.com/p/as3syndicationlib/downloads/list/" title="as3syndicationlib at google code!">download source</a>, browse the archive xmlsyndicationlib/bin/ and extract the xmlsyndication.swc into the libs folder of your flex project. It should result in the following structure:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/2.JPG" alt="Project Libs Path" width="219" height="146" /></div>
<p>This library file will be automatically loaded because it&#8217;s in the libs folder. You don&#8217;t need to do anything else to load this library, you just need to import its classes before use. (Note, if you do not have the bin-release folder don&#8217;t get worried, this is not important for now!).</p>
<h2>Step 3: Defining Project Details</h2>
<p>In this step, you&#8217;ll setup some folders that we&#8217;ll use along with our project. The first one is a folder &quot;assets&quot; in the project root (src folder). To create it just right-click on the src folder, then go to (New &gt; Folder) and name it &quot;assets&quot;.</p>
<p>Repeat the same actions for a &quot;com&quot; folder.</p>
<p>When this is done, extract the images provided in the <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/images.zip" title="Project Images">images.zip</a> file to the assets folder (you can select them and drag them to the assets folder in flex builder). You should now have the following structure in the flex navigator project:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/3.JPG" alt="Project Libs Path" width="241" height="239" /></div>
<h2>Step 4: Creating a Simple Layout</h2>
<p>This &quot;Simple layout&quot; can be whatever you want, it just needs to contain a datagrid, a textinput with feed address, a button to load and another to refresh. To get my layout:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/4.JPG" alt="Project Libs Path" width="598" height="320" /></div>
<p>you&#8217;ll need to insert the following code into WFlexibleFeed.mxml within the &lt;mx:Application&gt; tags:</p>
<pre name="code" class="javascript">&lt;mx:Canvas width=&quot;336&quot; height=&quot;208&quot; horizontalCenter=&quot;0&quot; verticalCenter=&quot;0&quot; borderColor=&quot;#A70101&quot; backgroundColor=&quot;#242424&quot;&gt;
		&lt;mx:Canvas x=&quot;0&quot; y=&quot;0&quot; width=&quot;336&quot; height=&quot;24&quot; backgroundColor=&quot;#333333&quot;&gt;
			&lt;mx:Label x=&quot;9&quot; y=&quot;4&quot; text=&quot;WFlexible Feed v1.0&quot; width=&quot;298&quot; color=&quot;#BBBBBB&quot;/&gt;
		&lt;/mx:Canvas&gt;
		&lt;mx:Label x=&quot;11&quot; y=&quot;27&quot; text=&quot;Feed:&quot; color=&quot;#FFFFFF&quot;/&gt;
		&lt;mx:Image x=&quot;310&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Rss.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Switch Feed!&quot; click=&quot;switchFeed()&quot;/&gt;
		&lt;mx:Image x=&quot;291&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Refresh.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Refresh&quot; click=&quot;refresh()&quot;/&gt;
		&lt;mx:Image x=&quot;50&quot; y=&quot;103&quot; source=&quot;@Embed(source='assets/logo.png')&quot;/&gt;
		&lt;mx:DataGrid x=&quot;10&quot; y=&quot;47&quot; height=&quot;155&quot; width=&quot;316&quot; id=&quot;dataGridItems&quot; dataProvider=&quot;{DP}&quot; useHandCursor=&quot;true&quot;  backgroundAlpha=&quot;0.4&quot;&gt;
			&lt;mx:columns&gt;
				&lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
			&lt;/mx:columns&gt;
		&lt;/mx:DataGrid&gt;
		&lt;mx:TextInput x=&quot;56&quot; y=&quot;26&quot; width=&quot;227&quot; text=&quot;http://feedproxy.google.com/flashtuts/&quot; height=&quot;20&quot; toolTip=&quot;Click to Edit Feed URL&quot; id=&quot;feedURI&quot; styleName=&quot;myTextInput&quot;/&gt;

	&lt;/mx:Canvas&gt;</pre>
<p>As you can see, I&#8217;ve already made some modifications into some components arguments, like giving a <b>DP</b> variable to dataGrid dataProvider, putting the feed addresse&#8230; well.. you can see for yourself. These are the main project components, we&#8217;ll use a little of CSS code (yes, Flex supports css) to make it more beautiful.</p>
<h2>Step 5: Creating a Stylesheet</h2>
<p>This process is very simple. Copy my css code here to make it similar. If you want some other colors, just try the <a href="http://examples.adobe.com/flex3/consulting/styleexplorer/Flex3StyleExplorer.html" title="Flex 3 Style Explorer">Flex 3 style explorer</a> and create your own css styles.</p>
<p>Copy this css into your application, right after the &lt;mx:Application&gt; tag:</p>
<pre name="code" class="css">&lt;mx:Style&gt;
.myTextInput {
   borderStyle: none;
   borderColor: #505050;
   backgroundAlpha: 0;
   backgroundColor: #ffffff;
   color: #5C5C5C;
   themeColor: #FFFFFF;
}
Button {
   cornerRadius: 0;
   borderColor: #000000;
   themeColor: #333333;
}
Alert {
backgroundColor: #000000;
borderColor: #000000;
backgroundAlpha: 0.9;
borderAlpha: 0.9;
color: #FFFFFF;
}
ToolTip {
   backgroundColor: #333333;
   color: #cccccc;
}
	DataGrid {
   backgroundAlpha: 1;
   backgroundColor: #666666;
   alternatingItemColors: #666666, #333333;
   headerColors: #000000, #000000;
   horizontalGridLines: true;
   horizontalGridLineColor: #000000;
   verticalGridLines: false;
   verticalGridLineColor: #cccccc;
   rollOverColor: #ffffff;
   textRollOverColor: #000000;
   borderColor: #000000;
   selectionColor: #ffffff;
   color: #ffffff;
   headerStyleName: &quot;mydataGridHeaderStyle&quot;;
}
.mydataGridHeaderStyle {
  color: #ffffff;
  fontWeight: normal;
  fontStyle: italic;
  textDecoration: none;
  letterSpacing: 1;
  }

VScrollBar {
  cornerRadius: 0;
  highlightAlphas: 0.46, 0.27;
  fillAlphas: 1, 1, 1, 1;
  fillColors: #666666, #333333, #cccccc, #999999;
  trackColors: #666666, #333333;
  themeColor: #000000;
  borderColor: #000000;
  iconColor: #111111;
  thumbOffset: 1;
}
&lt;/mx:Style&gt;</pre>
<p>This will produce a better widget look and feel, right?</p>
<h2>Step 6: Create the Feed Handler</h2>
<p>Yes, even with the xmlsyndication lib you&#8217;ll need to code a class to handle the parser output, or you&#8217;ll get nothing to work. So, you&#8217;ll need to create a new Action Script Class, just go to menu File &gt; New &gt; Action Script Class and enter the settings as seen in the image below. We&#8217;ll also need a class (from corelib) to validate the XML format. Just download the class <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/XMLUtil.zip" title="XMLUtil from corelib project">here</a> and put it in your &quot;com&quot; folder.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/5.JPG" alt="Project Libs Path" width="501" height="436" /></div>
<p>This will create a new folder &quot;feed&quot; in the &quot;com&quot; folder and a &quot;FeedParser.as&quot; file too. The Action Script editor will now open.</p>
<h2>Step 7: Code the Parser Class</h2>
<p>Just copy this code into the FeedParser.as Class:</p>
<pre name="code" class="javascript">package com.feed
  {
  //necessary imports
  import com.XMLUtil; //usefull for correct xml format XMLUtil.as from corelibPackage
  import com.adobe.xml.syndication.atom.Atom10; //imports from xmlsyndicationlib from adobe
  import com.adobe.xml.syndication.atom.Entry;
  import com.adobe.xml.syndication.rss.Item20;
  import com.adobe.xml.syndication.rss.RSS20;

  //some flash imports needed to work with the feed
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.IOErrorEvent;
  import flash.events.SecurityErrorEvent;
  import flash.net.URLLoader;
  import flash.net.URLRequest;
  import flash.net.URLRequestMethod;

  //two classes used in the process
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;

  public class FeedParser extends Sprite
  {
  private var feedURI:String=&quot;http://feedproxy.google.com/flashtuts/&quot;; //default feed
  private var feedLoader:URLLoader; //the feed loader
  public var FEED_DATA:ArrayCollection=null; //the feed data

  public function FeedParser(url:String)
  {
  feedURI=url; //on initiate, set the feed url
  }

  public function loadFeed():void {
   //add the listener events and load the feed
   feedLoader = new URLLoader();
   var req:URLRequest = new URLRequest(feedURI);
   req.method = URLRequestMethod.GET;
   feedLoader.addEventListener(Event.COMPLETE, completeHandler);
   feedLoader.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
   feedLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, errorHandler);
   feedLoader.load(req);
  }

  //error handling function
 private function errorHandler(e:Event):void {
  if(e.type==SecurityErrorEvent.SECURITY_ERROR) Alert.show(&quot;Security Error while reading feed URI!&quot;);
  else if(e.type==IOErrorEvent.IO_ERROR) Alert.show(&quot;I/O Error while reading feed URI!&quot;);
  else Alert.show(e.type+&quot; Error while reading feed URI!&quot;);
  }

  //on result function
  private function completeHandler(evt:Event):void {
  var feedData:String=feedLoader.data; //get the feed contents
  var feed_type:String=&quot;RSS&quot;;
  var entrys:Array;
  var tempObj:Object;

  //old way to detect feed type &amp; version
  if(feedData.search(&quot;rss version=\&quot;2.0\&quot;&quot;)&gt;-1) trace(&quot;FEED RSS 2.0&quot;);
  else if(feedData.search(&quot;rss version=&quot;)&gt;-1) trace(&quot;FEED RSS &lt;=1.0&quot;);
  else if(feedData.search(&quot;Atom&quot;)&gt;-1) trace(&quot;FEED ATOM&quot;);

  if(feedData.search(&quot;xmlns=\&quot;http://www.w3.org/2005/Atom&quot;)&gt;-1) feed_type=&quot;ATOM&quot;; //check if is an ATOM feed

 //if is a RSS feed
  if(feed_type==&quot;RSS&quot;) {
   var rss:RSS20= new RSS20();
   try { rss.parse(feedData); }  //parse it
   catch(e:Error) {
    Alert.show(&quot;Error Parsing Feed!\nInvalid link?&quot;);
    return void;
  } 

  entrys=rss.items; //get the items
  FEED_DATA = new ArrayCollection(); //initiate the arrayCollection

  //validate the feed
  if(!XMLUtil.isValidXML(feedData)) {
   Alert.show(&quot;Invalid or bad feed URI or structure!&quot;);
   return void;
  } 

  //built an array Collection with the results
  for each(var entry:Item20 in entrys)
  {
   tempObj = new Object();
   tempObj.title=entry.title;
   tempObj.link=entry.link;
   tempObj.desc=entry.description;
   tempObj.author=entry.creator;
   FEED_DATA.addItem(tempObj);
   }
  }
else if(feed_type==&quot;ATOM&quot;) { //else if is a ATOM feed, do the same process
  var rssA:Atom10 = new Atom10()
  try { rssA.parse(feedData); }
  catch(e:Error) {
   Alert.show(&quot;Error Parsing Feed!\nInvalid link?&quot;);
   return void;
  } 

  var entrysA:Array = rssA.entries;
  var tempObj2:Object;
  FEED_DATA = new ArrayCollection();

  if(!XMLUtil.isValidXML(feedData)) {
   Alert.show(&quot;Invalid / bad feed URI or structure!&quot;);
   return void;
  } 

  for each(var entryA:Entry in entrysA)
  {
   tempObj2 = new Object();
   tempObj2.title=entryA.title;
   tempObj2.link=entryA.links[0].href;
   tempObj2.desc=entryA.content;
   tempObj2.author=entryA.authors;
   FEED_DATA.addItem(tempObj2);
   }
  }
  else { //impossible to find feed type...
    Alert.show(&quot;Cannot detect feed type\nInvalid link?&quot;)
   return void;
  }

  this.dispatchEvent(new Event(&quot;DataReady&quot;)); //data is now ready to be used! listen this event to acess data!
  }
 }
}
</pre>
<p>Save your file now!</p>
<h2>Step 8: Understanding the Feed Parser</h2>
<p>Easy, just read the comments in the code and you&#8217;ll be able to understand it. If you don&#8217;t want to, you just need to know what we&#8217;ll write to use it: </p>
<pre name="code" class="javascript">
import com.feed.FeedParser;		

private var parser:FeedParser;

parser = new FeedParser(&quot;http://feed.url/feed/&quot;);
parser.addEventListener(&quot;DataReady&quot;, dataHandler);
parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
parser.loadFeed();
</pre>
<p>Well, this is a simplified version of how to work with our class. We&#8217;ll see it in use&#8230; keep following the tutorial..</p>
<h2>Step 9: Take a Break</h2>
<p>This is a relaxing step, maybe that was too much code at once, let me explain the workflow:</p>
<p>We have a syndicationlib responsible for reading the feed and putting the contents into an objects class. Our FeedParser class&#8217; main purpose is to prepare, call and handle the output from the syndication class.</p>
<p>Then there&#8217;s our main application, which will call the FeedParser class and wait for the DataReady event to load the feed items into the datagrid dataprovider.</p>
<h2>Step 10: Code First Load Function</h2>
<p>This is the function that will make our feed reader work. We&#8217;ll code an init() function which will be called on the creationComplete event of our application.</p>
<p>Write necessary imports:</p>
<pre name="code" class="javascript">
import mx.collections.ArrayCollection;
import mx.controls.Alert;

import com.feed.FeedParser;

private var parser:FeedParser;
private var currentFeed:String;

[Bindable]
private var DP:ArrayCollection;
</pre>
<p>Our initial function:</p>
<pre name="code" class="javascript">
private function init():void {
	DP=null;
	Security.allowDomain(feedURI.text); //useful some times, try to avoid domain access errors
	Security.allowInsecureDomain(feedURI.text); //useful some times, try to avoid domain access errors
	//in some cases you'll need (if possible) to load an external crossdomain.xml file... 

	parser = new FeedParser(feedURI.text);
	parser.addEventListener(&quot;DataReady&quot;, dataHandler);
	parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
	parser.loadFeed();
}
</pre>
<h2>Step 11: Code the Event Handlers</h2>
<p>Lets code the 3 necessary event handlers.</p>
<p>The error handler:</p>
<pre name="code" class="javascript">
private function dataErrorHandler(evt:Event):void {
	Alert.show(&quot;Some Error ocurred reading data from feed!\n\nPossible Causes:\nInvalid feed URL\nInvalid feed type (Not RSS 2.0)\nInvalid feed format&quot;);
}
</pre>
<p>The success handler:</p>
<pre name="code" class="javascript">
private function dataHandler(evt:Event):void {
	DP = new ArrayCollection();
	DP=parser.FEED_DATA;
	currentFeed=feedURI.text; //we save the feedURL to a variable, needed to refresh the feed and avoid recalls
}
</pre>
<p>Now we have our feed items in the DP arrayCollection, ready to use into the dataGrid. I also want to have a self-refresh mechanism (so the feed entries updates are outputted to datagrid), we&#8217;ll create it now.</p>
<h2>Step 12: Coding a Self-Update Mechanism</h2>
<p>The process is very easy, we&#8217;ll need a timer to execute a new call to get feed contents, so&#8230;</p>
<p>Declare the timer next to our var parser:</p>
<pre name="code" class="javascript">
private var updateTimer:Timer = new Timer(600000);
 //means 600 seconds = 10 minutes</pre>
<p>Write loadAutoUpdate(); on the dataHandler function on bottom:</p>
<pre name="code" class="javascript">
private function dataHandler(evt:Event):void {
	DP = new ArrayCollection();
	DP=parser.FEED_DATA;
	currentFeed=feedURI.text; //we save the feedURL to a variable, needed to refresh the feed and avoid recalls
	loadAutoUpdate(); //load the update engine
}
</pre>
<p>and let&#8217;s code the update function:</p>
<pre name="code" class="javascript">
private function loadAutoUpdate():void {
	try {
		updateTimer.stop(); //we try to stop a possible started timer
		updateTimer.removeEventListener(TimerEvent.TIMER, onTime); //remove the eventListener
	}
	catch(e:Error) { trace(&quot;Error on timer!&quot;) } //handle possible errors

	updateTimer.addEventListener(TimerEvent.TIMER, onTime); //add listener again
	updateTimer.start(); //start the timer
}
</pre>
<p>Finally, we need the onTime function to handle time events every 10 minutes:</p>
<pre name="code" class="javascript">
private function onTime(evt:TimerEvent):void {
	feedURI.text=currentFeed;
	init();
}
</pre>
<p>As people can change the feedURI field, we save it into a currentFeed variable until a new feed data is parsed.</p>
<h2>Step 13: Understanding the Self-Update Mechanism</h2>
<p>The workflow is simple. When the init() function is called, the feedParser is loaded.</p>
<p>In this function we reset the DP (data provider), setup the security policies (to avoid some domain access errors) and load the feed:</p>
<pre name="code" class="javascript">
(...)
parser.loadFeed();
(...)
</pre>
<p>Finally, the feed is parsed and the DP is populated with feed items:</p>
<pre name="code" class="javascript">
(...)
DP = new ArrayCollection();
DP=parser.FEED_DATA;
(...)
</pre>
<p>and we load the update mechanism that will be loaded every 10 minutes (~600 seconds / 600 000 miliseconds):</p>
<pre name="code" class="javascript">
(...)
private var updateTimer:Timer = new Timer(600000);
(...)
updateTimer.start();
(...)
</pre>
<p>That will call the onTime function every 10 minutes and recall the init function to reload the feed.</p>
<pre name="code" class="javascript">
private function onTime(evt:TimerEvent):void {
	feedURI.text=currentFeed;
	init();
}
</pre>
<p>The main system is coded, now we just need to add some more actions.</p>
<h2>Step 14: Code Button Actions</h2>
<p>In this step we&#8217;ll need to code the functions to change to a new feed and refresh the current one.</p>
<p>The refresh function in quite simple: </p>
<pre name="code" class="javascript">
private function refresh():void {
	feedURI.text=currentFeed; //to avoid changes on textInput
	init(); //reload the feed
}
</pre>
<p>and the change feed function:</p>
<pre name="code" class="javascript">
private function switchFeed():void {
	if(currentFeed==feedURI.text) Alert.show("Please edit the feed url and try again!"); //we'll not switch feed to the same one!
	else init(); //load the feed because feedURI.text is not equal to actual feed URI.
}
</pre>
<h2>Step 15: Load the Things Up and Test Them</h2>
<p>We need to load the whole process on the creationComplete event of the application, just add to your mx:application tag:</p>
<pre name="code" class="javascript">
(...) creationComplete="init()" (...)
</pre>
<p>Try to run the application now! It&#8217;s working, right? We&#8217;ll now improve the application interaction..</p>
<h2>Step 16: Understanding the DP Elements</h2>
<p>The data provider <b>DP</b> is a copy from the FeedParser.FEED_DATA array collection, so we need to add the FEED_DATA structure into the FeedParser.as class:</p>
<pre name="code" class="javascript">
	tempObj = new Object();
   tempObj.title=entry.title;
   tempObj.link=entry.link;
   tempObj.desc=entry.description;
   tempObj.author=entry.creator;
   FEED_DATA.addItem(tempObj);
</pre>
<p>In here we can see each item contains one title, link, desc(ription) and author(s) elements. This will be useful if you want to display that information on the datagrid, though for the moment we only want to display the title (using dataField):</p>
<pre name="code" class="javascript">
&lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
</pre>
<p>If we need to display the <b>desc</b> or<b> link</b>, we just need to provide the field <b>desc</b> as dataField parameter in a new column.</p>
<h2>Step 17: Load the Item Webpage</h2>
<p>Of course, this is very useful! We just need to enable the double-click into the dataGrid by writing the following into the mx:Table tag:</p>
<pre name="code" class="javascript">doubleClickEnabled=&quot;true&quot; doubleClick=&quot;loadURL()&quot;</pre>
<p>and the loadURL() function: </p>
<pre name="code" class="javascript">
private function loadURL():void {
	if(dataGridItems.selectedIndex>-1) navigateToURL(new URLRequest(dataGridItems.selectedItem.link), "_blank"); //if there is any selected index, load the URL into another window.
}
</pre>
<p>Quite easy, so we&#8217;ve almost finished the feedReader, time to review the code.</p>
<h2>Step 18: Review the Code</h2>
<p>Time to compare your code with mine</p>
<p><strong>WFlexibleFeed.xmml</strong></p>
<pre name="code" class="javascript">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
  &lt;mx:Application xmlns:mx=&quot;http://www.adobe.com/2006/mxml&quot; layout=&quot;absolute&quot; backgroundGradientAlphas=&quot;[1.0, 1.0]&quot; backgroundGradientColors=&quot;[#EBEBEB, #CBCBCB]&quot; creationComplete=&quot;init()&quot;&gt;
  &lt;mx:Style&gt;
  .myTextInput {
  borderStyle: none;
  borderColor: #505050;
  backgroundAlpha: 0;
  backgroundColor: #ffffff;
  color: #5C5C5C;
  themeColor: #FFFFFF;
  }
  Button {
  cornerRadius: 0;
  borderColor: #000000;
  themeColor: #333333;
  }
  Alert {
  backgroundColor: #000000;
  borderColor: #000000;
  backgroundAlpha: 0.9;
  borderAlpha: 0.9;
  color: #FFFFFF;
  }

  ToolTip {
  backgroundColor: #333333;
  color: #cccccc;
  }

  DataGrid {
  backgroundAlpha: 1;
  backgroundColor: #666666;
  alternatingItemColors: #666666, #333333;
  headerColors: #000000, #000000;
  horizontalGridLines: true;
  horizontalGridLineColor: #000000;
  verticalGridLines: false;
  verticalGridLineColor: #cccccc;
  rollOverColor: #ffffff;
  textRollOverColor: #000000;
  borderColor: #000000;
  selectionColor: #ffffff;
  color: #ffffff;
  headerStyleName: &quot;mydataGridHeaderStyle&quot;;
  }

.mydataGridHeaderStyle {
  color: #ffffff;
  fontWeight: normal;
  fontStyle: italic;
  textDecoration: none;
  letterSpacing: 1;
}

VScrollBar {
  cornerRadius: 0;
  highlightAlphas: 0.46, 0.27;
  fillAlphas: 1, 1, 1, 1;
  fillColors: #666666, #333333, #cccccc, #999999;
  trackColors: #666666, #333333;
  themeColor: #000000;
  borderColor: #000000;
  iconColor: #111111;
  thumbOffset: 1;
}

&lt;/mx:Style&gt;

&lt;mx:Script&gt;
  &lt;![CDATA[
  import mx.collections.ArrayCollection;
  import mx.controls.Alert;

  import com.feed.FeedParser;

  private var parser:FeedParser;
  private var updateTimer:Timer = new Timer(600000);

  [Bindable]
  private var DP:ArrayCollection;

  private var currentFeed:String;

  private function init():void {
   DP=null;
   Security.allowDomain(feedURI.text);
   Security.allowInsecureDomain(feedURI.text);
   parser = new FeedParser(feedURI.text);
   parser.addEventListener(&quot;DataReady&quot;, dataHandler);
   parser.addEventListener(&quot;DataError&quot;, dataErrorHandler);
   parser.loadFeed();
  }

  private function dataErrorHandler(evt:Event):void {
   Alert.show(&quot;Some Error ocurred reading data from feed!\n\nPossible Causes:\nInvalid feed URL\nInvalid feed type (Not RSS 2.0)\nInvalid feed format&quot;);
  }

  private function loadAutoUpdate():void {
   try {
    updateTimer.stop();
    updateTimer.removeEventListener(TimerEvent.TIMER, onTime);
   }
   catch(e:Error) { }

    updateTimer.addEventListener(TimerEvent.TIMER, onTime);
    updateTimer.start();
  }

  private function onTime(evt:TimerEvent):void {
    feedURI.text=currentFeed;
    init();
  }

  private function dataHandler(evt:Event):void {
    DP = new ArrayCollection();
    DP=parser.FEED_DATA;
    currentFeed=feedURI.text;
    loadAutoUpdate();
  }

  private function loadURL():void {
   if(dataGridItems.selectedIndex&gt;-1) navigateToURL(new URLRequest(dataGridItems.selectedItem.link), &quot;_blank&quot;);
  }

  private function refresh():void {
    feedURI.text=currentFeed;
    init();
  }

  private function switchFeed():void {
    if(currentFeed==feedURI.text) Alert.show(&quot;Please edit the feed url and try again!&quot;);
    else init();
  }

  ]]&gt;
  &lt;/mx:Script&gt;

  &lt;mx:Canvas width=&quot;336&quot; height=&quot;208&quot; horizontalCenter=&quot;0&quot; verticalCenter=&quot;0&quot; borderColor=&quot;#A70101&quot; backgroundColor=&quot;#242424&quot;&gt;
    &lt;mx:Canvas x=&quot;0&quot; y=&quot;0&quot; width=&quot;336&quot; height=&quot;24&quot; backgroundColor=&quot;#333333&quot;&gt;
     &lt;mx:Label x=&quot;9&quot; y=&quot;4&quot; text=&quot;WFlexible Feed v1.0&quot; width=&quot;298&quot; color=&quot;#BBBBBB&quot;/&gt;
    &lt;/mx:Canvas&gt;
   &lt;mx:Label x=&quot;11&quot; y=&quot;27&quot; text=&quot;Feed:&quot; color=&quot;#FFFFFF&quot;/&gt;
   &lt;mx:Image x=&quot;310&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Rss.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Switch Feed!&quot; click=&quot;switchFeed()&quot;/&gt;
   &lt;mx:Image x=&quot;291&quot; y=&quot;25&quot; source=&quot;@Embed(source='assets/Refresh.png')&quot; useHandCursor=&quot;true&quot; buttonMode=&quot;true&quot; toolTip=&quot;Refresh&quot; click=&quot;refresh()&quot;/&gt;
   &lt;mx:Image x=&quot;50&quot; y=&quot;103&quot; source=&quot;@Embed(source='assets/logo.png')&quot;/&gt;
   &lt;mx:DataGrid x=&quot;10&quot; y=&quot;47&quot; height=&quot;155&quot; width=&quot;316&quot; id=&quot;dataGridItems&quot; dataProvider=&quot;{DP}&quot; doubleClickEnabled=&quot;true&quot; doubleClick=&quot;loadURL()&quot; useHandCursor=&quot;true&quot;  backgroundAlpha=&quot;0.4&quot;&gt;
    &lt;mx:columns&gt;
      &lt;mx:DataGridColumn headerText=&quot;Feed entries...&quot; dataField=&quot;title&quot; sortable=&quot;false&quot;/&gt;
     &lt;/mx:columns&gt;
   &lt;/mx:DataGrid&gt;
  &lt;mx:TextInput x=&quot;56&quot; y=&quot;26&quot; width=&quot;227&quot; text=&quot;http://feedproxy.google.com/flashtuts/&quot; height=&quot;20&quot; toolTip=&quot;Click to Edit Feed URL&quot; id=&quot;feedURI&quot; styleName=&quot;myTextInput&quot;/&gt;
 &lt;/mx:Canvas&gt;

&lt;/mx:Application&gt;</pre>
<p>It&#8217;s almost equal right?</p>
<h2>Step 19: Prepare the Application for Web</h2>
<p>Many people will grab the generated WFlexibleFeed.swf from the bin-debug folder and put it in the final production environment, but this is a mistake!</p>
<p>First, use the framework (near 200kb) as RSL (Runtime Shared Library). That will then be downloaded just once to the user&#8217;s machine, next time it will not be loaded (therefore decreasing loading time). To do this, goto Project &gt; Properties &gt; Flex Build Path &gt; Library Path and click on Framework Linkage. Change it from &quot;Merged into code&quot; to &quot;Runtime shared library (RSL)&quot; then click <b>OK</b>. The framework will now be exported as a separated file.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/7.JPG" alt="Framework linkage" width="495" height="231" /></div>
<p>We&#8217;re ready to export the application.</p>
<h2>Step 20: Export Release Build</h2>
<p>Every application should be exported as a release build (that&#8217;s why  project path contains the bin-release folder). You just need to click on the Export Release Build Button, shown yellow here:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/6.JPG" alt="Export Release Build" width="553" height="40" /></div>
<p>The whole project will be exported to the &quot;bin-release&quot; folder. These are the contents to be placed on your site or blog! </p>
<h2>Step 21: Play With It</h2>
<p>You now have time to play with the final result, change some css details, make another kind of feed switcher, there are many things you can improve it. You can even take it to desktop using Adobe AIR. Get inspired! One very nice application for this feedReader is to put your own feed URL, disable text edition, disable the change and refresh buttons and distribute to other sites as a widget to read your blog entries&#8230;</p>
<h2>Conclusion</h2>
<p>In this tutorial you&#8217;ve learned how to parse, handle and display feed entries into a DataGrid inside Flash. You&#8217;ve learned a little about the cool xmlsyndication lib and also dicovered some tricks to improve your projects. Browse the code, download the <a href="http://flashtuts.s3.cdn.plus.org/060_FlexRSSFeedGadget/source.zip" title="Project to import into Flex Builder">source files</a> and have fun!</p>
<p>Note: use the menu File &gt; Import &gt; Flex Project archive to import the source files; they are ready to use!</p>
<p>I hope you liked this tutorial, thanks for reading!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/flex/creating-a-feed-reader-widget-with-adobe-flex-3/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Assemble a Nifty Twitter Widget using Flash and the Twitter API</title>
		<link>http://active.tutsplus.com/tutorials/screencasts/assemble-a-nifty-twitter-widget-using-flash-and-the-twitter-api/</link>
		<comments>http://active.tutsplus.com/tutorials/screencasts/assemble-a-nifty-twitter-widget-using-flash-and-the-twitter-api/#comments</comments>
		<pubDate>Fri, 08 May 2009 12:00:54 +0000</pubDate>
		<dc:creator>Shane Johnson</dc:creator>
				<category><![CDATA[Screencasts]]></category>
		<category><![CDATA[Widgets]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=594</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/024_TwitterWidget/previewImage.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Flash will work neatly in combination with the <a href="http://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses-user_timeline" target="_blank">Twitter API</a> to create a Twitter widget for any webpage. Follow Shane Johnson (<a href="http://twitter.com/ultravisual" target="_blank">@ultravisual</a>) as he demonstrates building an interface, pulling in specific XML data and tackling cross-domain policy issues..</p>
<p><span id="more-594"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/024_TwitterWidget/Twitter_Widget_Video.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/screen.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/024_TwitterWidget/Twitter_Widget_src.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/024_TwitterWidget/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h3>View Screencast</h3>
<p>

<div class="tutorial_image">
		<div id="player10"><a href="http://get.adobe.com/flashplayer/">Get the Flash Player</a> to see this player.</div>
		<script type="text/javascript">
		var so = new SWFObject('http://active.tutsplus.com/wp-content/plugins/flash-player/player.swf','player10','600','450','9');
		so.addParam('allowscriptaccess','always');
		so.addParam('allowfullscreen','true');
		so.addParam('flashvars','&file=http://flashtuts.s3.cdn.plus.org/024_TwitterWidget/Twitter_Widget_Video.flv&bufferlength=1&skin=http://active.tutsplus.com/wp-content/plugins/flash-player/silver.swf&fullscreen=true');
		so.write('player10');
		</script>
		</div>

</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/screencasts/assemble-a-nifty-twitter-widget-using-flash-and-the-twitter-api/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.300 seconds -->
