MERGE 2 ONE MEDIA

Saturday, November 22, 2008

RSS Widget - AS3

Here is a simple RSS widget/droplet whatever you want to call it. It loads RSS feeds into Flash.

Download the source files here.

The proxy file is written in PHP using curl.

You can't cross load files from one server to another so the proxy.php file make it look like the request is coming from your own server.

Curl is an awesome PHP library that can do a lot more than this. I also use it to scrap MLS listings for real estate clients to manage their properties. Check out a demo here.

You also have to add the crossdomain.xml file to the root of your server. Here's a link to security in Flash.

Here is the xml file that has all the links to my RSS feeds.

<?xml version="1.0" encoding="utf-8"?> <m21m:rsswidget xmlns:m21m='http://www.m21m.com/schema/m21m'> <m21m:rssfeeds> <m21m:feed image="images/blogger.gif" feed="http://www.m21m.com/rss.xml" /> <m21m:feed image="images/twitter.gif" feed="http://twitter.com/statuses/user_timeline/14305992.rss"/> </m21m:rssfeeds> </m21m:rsswidget>

I will load this file to get all the feed attributes. You can add whatever RSS links and images you want just add another feed node with a feed attribute to your new RSS feed. I tried to add my Facebook RSS feed but gave up after to many problems with their security. If you can figure out how to make it work please post your solution in the comments.

You can read my other blog post to see how I load all the xml files into arrays.

Here is my actionscript code.

//import the Scroll class import com.m21m.util.Scroll; //add scrolling to the main_mc var sb:Scroll = new Scroll(main_mc); //total feeds to show per rss var TOTALPERFEED = 6; //be sure to change this. var PROXY = "http://yoursite.com/proxy.php?url="; //array to hold all the rss links from rss-widget.xml var xmlManifest:Array = new Array(); //array to hold each xml file var xmlDocs:Array = new Array(); //the xml file to be loaded. var rssWidgetRequest:URLRequest = new URLRequest("xml/rss-widget.xml"); var urlLoader:URLLoader = new URLLoader(); //all my xml files var docsXML:XML = new XML(); docsXML.ignoreWhitespace = true; //load rss-widget.xml and when COMPLETE run function loadDocs urlLoader.addEventListener(Event.COMPLETE,loadDocs); urlLoader.load(rssWidgetRequest); //images from the image attribute in m21m:feed image="images/twitter.gif" var images:Array = new Array(); //load the docs function loadDocs(event:Event):void { docsXML = XML(event.target.data); //m21m is the name space defined in my doc m21m:feed... var m21m:Namespace=docsXML.namespace("m21m"); //get all the feed nodes var feeds=docsXML..m21m::feed; for (var i:int=0; i < feeds.length(); ++i) { //add images from the image attribute and add it to the images array images[images.length] = feeds[i].attribute("image"); //add the feed to the xmlManifest array xmlManifest[xmlManifest.length] = feeds[i].attribute("feed"); } //load the xml for each doc loadXMLDocs(); } //load all the XML files function loadXMLDocs() { if (xmlManifest.length>xmlDocs.length) { var rssURL:URLRequest = new URLRequest(PROXY+xmlManifest[xmlDocs.length]); var urlLoader:URLLoader = new URLLoader(); var xmlDoc:XML = new XML(); xmlDoc.ignoreWhitespace = true; urlLoader.addEventListener(Event.COMPLETE,getDoc); urlLoader.load(rssURL); function getDoc(event:Event) { xmlDoc = XML(event.target.data); //hold all the xml of each doc in an array xmlDocs[xmlDocs.length] = xmlDoc; loadXMLDocs(); } } else { //create the feeds on the screen createFeeds(); } } function createFeeds():void { for (var t:int=0; t < xmlDocs.length; t++) { //get the XML for the files docsXML = XML(xmlDocs[t]); //get all the item nodes from the rss feeds var xmlList=docsXML..item; var totalLength:int; //check to see how many nodes to display per each feed if (xmlList.length() < TOTALPERFEED) { totalLength = xmlList.length(); } else { totalLength = TOTALPERFEED; } if (TOTALPERFEED >= 100) { totalLength = xmlList.length(); } for (var i:int=0; i < totalLength; i++) { //add are feed movieclip from the library var feed_mc:Feed = new Feed(); main_mc.content_mc.addChild(feed_mc); var loader =new Loader(); loader.load(new URLRequest(images[t])); feed_mc.loader_mc.addChild(loader); feed_mc.feed_txt.htmlText = "<a href='"+xmlList[i].link.text()+"'>"+ xmlList[i].title.text()+"</a>"; } } //order the feeds on the screen orderFeeds(); //garbage collection destroy(); } function orderFeeds() { //loop through the movieclips and stack them for (var i:int=1; i < main_mc.content_mc.numChildren; i++) { main_mc.content_mc.getChildAt(i).y = main_mc.content_mc.getChildAt(i - 1).y + main_mc.content_mc.getChildAt(i - 1).height + 1; } } //delete all variables function destroy() { xmlManifest = null; xmlDocs = null; rssWidgetRequest = null; urlLoader = null; docsXML = null; images = null; } //Custom Right Click Menu var myMenu:ContextMenu = new ContextMenu(); myMenu.hideBuiltInItems(); //Add You Blog or Links to your site. var menuItem:ContextMenuItem = new ContextMenuItem("www.m21m.com"); menuItem.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, goToURL); myMenu.customItems.push(menuItem); this.contextMenu = myMenu; function goToURL(e:ContextMenuEvent):void { var url:String = "http://www.m21m.com"; var request:URLRequest = new URLRequest(url); navigateToURL(request, '_blank'); }

The Scroll class can be used in any Flash file. You can skin it to look how you want or add to the code or whatever.

Add it to your file like this.

import com.m21m.util.Scroll; var sb:Scroll = new Scroll(main_mc);

The top part of the actionscript file is covered in this blog post so I'll start with the createFeeds() function. TOTALPERFEED is set at the top of the file and will set how many items to display per RSS feed. If you set TOTALPERFEED to 100 it will load all the RSS items that are in your RSS feed (more than 100 if there are more).

If you look in the library, feed_mc is the Feed movieclip in the library. You can skin it to look however you want. If you do let me know so I can see how it looks. If I had a ton of time I would make this look better, but just wanted to post this for learning purposes.

The orderFeeds() function stacks the feeds on top of each other.

The destroy() function deletes the xml and other variables. You probably don't have to do this, the Flash player eventually will do it's own garbage collection. Read more on garbage collection here.

I adding a link to the Context Menu (right click over the Flash movie). You can add however many you want. I figured someone might want that little piece of code.

If anyone has a better way to do anything let me know in the comments.

Labels: , , , ,

Thursday, November 20, 2008

Load Multiple XML Files - AS3

I've often built Flash apps that require multiple xml files to load. Here I'm going to show you how to dynamically load multiple RSS feeds into Flash.

Download the source files here.

Here is the xml file that has all the links to my RSS feeds.

<?xml version="1.0" encoding="utf-8"?> <m21m:RSSwidget xmlns:m21m='http://www.m21m.com/schema/m21m'> <m21m:RSSfeeds> <m21m:feed feed="xml/twitter.xml"/> <m21m:feed feed="xml/facebook.xml" /> <m21m:feed feed="xml/blogger.xml" /> </m21m:RSSfeeds> </m21m:RSSwidget>

I will load this file to get all the feed attributes. You can add whatever RSS link you want just add another feed node with a feed attribute to your new RSS feed.

I use "m21m" as a namespace in my xml. You can read about namespace here. Using a namespace is a habit for me now.

Here is my actionscript code.

//each xml file to load var xmlManifest:Array = new Array(); //the xml for each file var xmlDocs:Array = new Array(); //the xml file with all the xml files to be loaded. var RSSWidgetRequest:URLRequest = new URLRequest("xml/rss-widget.xml"); var urlLoader:URLLoader = new URLLoader(); var docsXML:XML = new XML(); docsXML.ignoreWhitespace = true; //when COMPLETE is loaded run function loadDocs urlLoader.addEventListener(Event.COMPLETE,loadDocs); urlLoader.load(RSSWidgetRequest); //load the docs function loadDocs(event:Event):void { docsXML = XML(event.target.data); //m21m is the name space defined in my doc m21m:feed... you don't need one. var m21m:Namespace=docsXML.namespace("m21m"); //get all the feed nodes var feeds=docsXML..m21m::feed; for (var i:int=0; i < feeds.length(); ++i) { //add the feed to the xmlManifest array xmlManifest[xmlManifest.length] = feeds[i].attribute("feed"); } //load the xml for each doc loadXMLDocs(); } //load all the XML files function loadXMLDocs() { if (xmlManifest.length>xmlDocs.length) { var RSSURL:URLRequest = new URLRequest(xmlManifest[xmlDocs.length]); var urlLoader:URLLoader = new URLLoader(); var xmlDoc:XML = new XML(); xmlDoc.ignoreWhitespace = true; urlLoader.addEventListener(Event.COMPLETE,getDoc); urlLoader.load(RSSURL); function getDoc(event:Event) { xmlDoc = XML(event.target.data); //hold all the xml of each doc in an array xmlDocs[xmlDocs.length] = xmlDoc; loadXMLDocs(); } } else { trace(xmlDocs) //do something when all xml is loaded } }

Starting from the top of the code. This is the array that will hold all my RSS files

var xmlManifest:Array = new Array();

I could also write my code like this and delete the loadDocs function but I want this file to work without having to open Flash.

var xmlManifest:Array = new Array("xml/twitter.xml", "xml/blogger.xml", "xml/facebook.xml");

This array will hold all all the xml for each xml file loaded

var xmlDocs:Array = new Array();

Load the rss-widget.xml xml file.

var RSSWidgetRequest:URLRequest = new URLRequest("xml/rss-widget.xml");

Pretty straight forward what this is. If you don't know go to Adobe Live Docs.

var urlLoader:URLLoader = new URLLoader();

This will hold the xml from my rss-widget.xml file.

var docsXML:XML = new XML(); docsXML.ignoreWhitespace = true;

Event Listener waits for the file to complete loading

urlLoader.addEventListener(Event.COMPLETE,loadDocs);

Load the URL.

urlLoader.load(RSSWidgetRequest);

When the xml has loaded loaded run this function

function loadDocs(event:Event):void {

The xml is loaded and a variable referenced

docsXML = XML(event.target.data);

m21m is the namespace defined in my doc <m21m:feed... you don't need one. I use this to define my namespace. Perhaps in the future I will want to add another doc or use my xml with a xsl template to create a different kind of app. Check out namespaces here.

var m21m:Namespace=docsXML.namespace("m21m");

This var holds all the feed nodes

var feeds=docsXML..m21m::feed; <m21m:feed feed="xml/twitter.xml"/> <m21m:feed feed="xml/facebook.xml" /> <m21m:feed feed="xml/blogger.xml" />

There are three feed nodes. Loop through them all.

for (var i:int=0; i < feeds.length(); ++i) {

Add each file to the xmlManifest array

xmlManifest[xmlManifest.length] = feeds[i].attribute("feed"); }

Load the xml for each doc using the loadXMLDocs() function

loadXMLDocs(); }

Run through and load all the xml for each xml file in the xmlManifest arrary

function loadXMLDocs() { if (xmlManifest.length>xmlDocs.length) {

Load the xml file. Same thing is going on here as is going on at the top of the file.

var RSSURL:URLRequest = new URLRequest(xmlManifest[xmlDocs.length]); var urlLoader:URLLoader = new URLLoader(); var xmlDoc:XML = new XML(); xmlDoc.ignoreWhitespace = true;

When complete run the getDoc function

urlLoader.addEventListener(Event.COMPLETE,getDoc); urlLoader.load(RSSURL); function getDoc(event:Event) { xmlDoc = XML(event.target.data);

Hold all the xml for each doc in an array

xmlDocs[xmlDocs.length] = xmlDoc; loadXMLDocs(); } } else {

Now you have all your RSS feeds in one array. You can do whatever you want with the data.

//trace(xmlDocs) } }

I'm going to add another blog with a completed RSS reader soon. If you have comments or questions leave them here in the comments. If you know of a better way to do things comment them also.

Labels: , , ,